/*
 * task.c
 *
 *   Copyright (c) 2008, Ueda Laboratory LMNtal Group <lmntal@ueda.info.waseda.ac.jp>
 *   All rights reserved.
 *
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions are
 *   met:
 *
 *    1. Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the
 *       distribution.
 *
 *    3. Neither the name of the Ueda Laboratory LMNtal Group nor the
 *       names of its contributors may be used to endorse or promote
 *       products derived from this software without specific prior
 *       written permission.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: task.c,v 1.37 2008/10/21 11:31:58 riki Exp $
 */


#include "task.h"
#include "atom.h"
#include "dumper.h"
#include "instruction.h"
#include "vector.h"
#include "symbol.h"
#include "functor.h"
#include "st.h"
#include "functor.h"
#include "error.h"
#include "ccallback.h"
#include "special_atom.h"
#include "hyperlink.h"
#include "slim_header/string.h"
#include "slim_header/memstack.h"
#include "slim_header/port.h"
#include "visitlog.h"
#include "delta_membrane.h"
#include "mc_worker.h"
#include "mc_generator.h"
#include "dpor.h"

#include "runtime_status.h"


typedef void (* callback_0)(LmnReactCxt *,
                            LmnMembrane *);
typedef void (* callback_1)(LmnReactCxt *,
                            LmnMembrane *,
                            LmnAtom, LmnLinkAttr);
typedef void (* callback_2)(LmnReactCxt *,
                            LmnMembrane *,
                            LmnAtom, LmnLinkAttr,
                            LmnAtom, LmnLinkAttr);
typedef void (* callback_3)(LmnReactCxt *,
                            LmnMembrane *,
                            LmnAtom, LmnLinkAttr,
                            LmnAtom, LmnLinkAttr,
                            LmnAtom, LmnLinkAttr);
typedef void (* callback_4)(LmnReactCxt *,
                            LmnMembrane *,
                            LmnAtom, LmnLinkAttr,
                            LmnAtom, LmnLinkAttr,
                            LmnAtom, LmnLinkAttr,
                            LmnAtom, LmnLinkAttr);


/**
  Javaによる処理系ではリンクはリンクオブジェクトで表現するが、SLIMでは
  リンクオブジェクトはなく直接リンク先のアトムと引数番号でリンクを表す。
  しかし、このSLIMの実装方法では，a(L,L).  a(X,Y) :- b(X), b(Y). の場合
  に2.のようになりうまくいかない。これは、GETLINKで得たリンクの値が
  INHERIT_LINK によるリンクのつなぎ替えの過程で更新されないからだ。そこ
  で、3.のようにしてGETLINK でのリンク先の取得を実際には遅延させるよう
  にして正常に動作させる案を考えた。

  現在は3.の方法を取っている。具体的には wtとatにリンク先のアトムと引数
  番号ではなくリンク元のアトムと引数番号を保持する。さらに、リンク元を
  保持している場合にはwt内の値の下位1ビットを1にし、リンク先を保持して
  いる場合と区別をしている。どちらの場合も同じマクロを使い同様のコード
  でリンク先の取得ができるようにしている。

  1. リンクオブジェクトがある場合(Javaによる処理系)

    0--+       0----b       0 +--b       +--b
    a  |  =>   a       =>   a |      =>  |
    1--+       1            1 +--b       +--b

  2. リンクオブジェクトがない場合(SLIM)
     A,BはGETLINKで得た、リンク先を表している

                  (Bの先を指す)    (Aの先を指す)    (不正な状態)
      A                A                  A               A
      |                |             b--> |          b--> |
  +---0<---+       +---0              <---0
  |   a    |  =>   |   a      =>          a      =>
  +-->1----+       +-->1--->              1--->
      |                |<-- b             |<-- b          |<-- b
      B                B                  B               B


  3. リンクオブジェクトがない場合、リンクはリンク元を保持(SLIM)
      A,BはGETLINKを行った際のリンク元の情報を持つ。実際のリンク先は
      リンクのつなぎ替えを行う際に得る。

             (Bのリンク先を得る)                (Aのリンク先を得る)  aが消滅
                                 +---------+      +---------+       +---------+-+      +-----------+
                                 |         |      |         |       |         | |      |           |
    B                B           v     B   |      v     B   |       v     B   | |      v           |
    |            b-->|           b     |   |      b     |   |       b     |   | |      b           |
  +---0<--+       +---0<--+      | +---0   |      | +---0   |       | +---0   | |      |           |
  |   a   |  =>   |   a   |  =>  | |   a   |  =>  | |   a   |  =>   | |   a   | | =>   |           |
  +-->1---+       +-->1---+      +-+-->1---+      +-+-->1---+       | +-->1---+ |      |           |
        |              |                |                |<--b      +------|--->b      +---------->b
        A              A                A                A                 A
*/

/* リンク先のアトムを得る */
#define LINKED_ATOM(LINKI) wt(rc, LINKI)
/* リンク先のアトムの引数のattributeを得る */
#define LINKED_ATTR(LINKI) at(rc, LINKI)

static inline BOOL react_ruleset(LmnReactCxt *rc, LmnMembrane *mem, LmnRuleSet ruleset);
static inline BOOL react_ruleset_inner(LmnReactCxt *rc, LmnMembrane *mem, LmnRuleSet rs);
static inline void react_initial_rulesets(LmnReactCxt *rc, LmnMembrane *mem);
static inline BOOL react_ruleset_in_all_mem(LmnReactCxt *rc, LmnRuleSet rs, LmnMembrane *mem);
static BOOL interpret(LmnReactCxt *rc, LmnRule rule, LmnRuleInstr instr);
static BOOL dmem_interpret(LmnReactCxt *rc, LmnRule rule, LmnRuleInstr instr);


static void mem_oriented_loop(LmnReactCxt *rc, LmnMembrane *mem);

void lmn_dmem_interpret(LmnReactCxt *rc, LmnRule rule, LmnRuleInstr instr)
{
  dmem_interpret(rc, rule, instr);
}


/** 通常実行時の入口.
 *  インタタラクティブ実行時の処理フローは以下の通り[yueno]
 *    1. 後始末     normal_cleaningフラグがたっている時
 *    2. 初期化     !(normal_remainモード時 && normal_remaining=ON) 時
 *    3. 処理       常に行う
 *    4. 後始末     通常モード時
 *    5. 継続フラグ 通常モードならON、normal_remainモードならOFFにセットする
 */
void lmn_run(Vector *start_rulesets)
{
  static LmnMembrane *mem;
  static LmnReactCxt mrc;

#ifdef TIME_OPT
  /* 通常実行では非決定実行とは異なりProcess IDを
   * 1から再割り当てする機会(状態圧縮と復元)が存在しない.
   * 破棄したProcessのIDを使い回す必要がある.
   * もし通常実行の並列化を考えるならばIDを再利用するためのMT-Safeな機構が必要 */
  if (!env_proc_id_pool()) {
    env_set_proc_id_pool(vec_make(64));
  }
#endif

  /* interactive: normal_cleaningフラグがONの場合は後始末 */
  if (lmn_env.normal_cleaning) {
    lmn_mem_drop(mem);
    lmn_mem_free(mem);
    mem_react_cxt_destroy(&mrc);
    lmn_env.normal_cleaning = FALSE;
  }

  /* interactive : (normal_remain時でnormal_remaining=ON)以外の場合は初期化 */
  if (!lmn_env.normal_remain && !lmn_env.normal_remaining) {
    mem_react_cxt_init(&mrc);
    mem = lmn_mem_make();
    RC_SET_GROOT_MEM(&mrc, mem);
  }
  lmn_memstack_push(RC_MEMSTACK(&mrc), mem);

  /** PROFILE START */
  if (lmn_env.profile_level >= 1) {
    profile_start_exec();
    profile_start_exec_thread();
  }

  react_start_rulesets(mem, start_rulesets);
  lmn_memstack_reconstruct(RC_MEMSTACK(&mrc), mem);

  if (lmn_env.trace) {
    if (lmn_env.output_format != JSON) fprintf(stdout, "%d: ", RC_TRACE_NUM_INC(&mrc));
    lmn_dump_cell_stdout(mem);
    if (lmn_env.show_hyperlink) lmn_hyperlink_print(mem);
  }

  mem_oriented_loop(&mrc, mem);

  /** PROFILE FINISH */
  if (lmn_env.profile_level >= 1) {
    profile_finish_exec_thread();
    profile_finish_exec();
  }
  if (lmn_env.dump) { /* lmntalではioモジュールがあるけど必ず実行結果を出力するプログラミング言語, で良い?? */
    if (lmn_env.sp_dump_format == LMN_SYNTAX) {
      fprintf(stdout, "finish.\n");
    } else {
      lmn_dump_cell_stdout(mem);
    }
  }
  if (lmn_env.show_hyperlink) lmn_hyperlink_print(mem);

  /* 後始末 */
  if (lmn_env.normal_remain) {
    lmn_env.normal_remaining = TRUE;
  } else {
    lmn_env.normal_remaining = FALSE;
    lmn_mem_drop(mem);
    lmn_mem_free(mem);
    mem_react_cxt_destroy(&mrc);
  }
#ifdef TIME_OPT
  if (env_proc_id_pool()) {
    vec_free(env_proc_id_pool());
  }
#endif

}


/** 膜スタックに基づいた通常実行 */
static void mem_oriented_loop(LmnReactCxt *rc, LmnMembrane *mem)
{
  LmnMemStack memstack = RC_MEMSTACK(rc);

  while(!lmn_memstack_isempty(memstack)){
    LmnMembrane *mem = lmn_memstack_peek(memstack);
    if (!react_all_rulesets(rc, mem)) {
      /* ルールが何も適用されなければ膜スタックから先頭を取り除く */
      lmn_memstack_pop(memstack);
    }
  }
}


/** cur_memに存在するルールすべてに対して適用を試みる
 * @see mem_oriented_loop (task.c)
 * @see expand_inner      (nd.c) */
BOOL react_all_rulesets(LmnReactCxt *rc, LmnMembrane *cur_mem)
{
  unsigned int i;
  struct Vector rulesets = cur_mem->rulesets; /* 本膜のルールセットの集合 */
  BOOL ok = FALSE;

  /* ルールセットの適用 */
  for (i = 0; i < vec_num(&rulesets); i++) {
    if (react_ruleset(rc, cur_mem, (LmnRuleSet)vec_get(&rulesets, i))) {
      /* ndでは失敗するまでマッチングバックトラックしているので必ずFALSEが返ってくる */
      ok = TRUE;
      break;
    }
  }

  /* 通常実行では, 適用が発生しなかった場合にシステムルールの適用を行う
   * ndではokはFALSEなので, system_rulesetが適用される. */
  ok = ok || react_ruleset_inner(rc, cur_mem, system_ruleset);

  return ok;
}


/* an extenstion rule applier, @see ext/atomic.c */
extern BOOL react_ruleset_atomic(LmnReactCxt *rc,
                                 LmnMembrane *mem,
                                 LmnRuleSet  rs);

/** 膜memに対してルールセットrsの各ルールの適用を試みる.
 *  戻り値:
 *   通常実行では, 書換えに成功した場合にTRUE, マッチングしなかった場合にFALSEを返す.
 *   非決定実行では常にFALSEを返す(マッチングに失敗するまでバックトラックする仕様). */
static inline BOOL react_ruleset(LmnReactCxt *rc,
                                 LmnMembrane *mem,
                                 LmnRuleSet rs)
{
  BOOL result;

  if (RC_IS_ATOMIC_STEP(rc)) {
    /* atomic_step時: atomic stepが複数ある場合,
     *               atomic適用中のrulesetとそうでないものを区別する必要がある */
    if (lmn_ruleset_is_valid_atomic(rs)) {
      result = react_ruleset_inner(rc, mem, rs);
    } else {
      result = FALSE;
    }
  }
  else if (lmn_ruleset_atomic_type(rs) == ATOMIC_NONE) {
    result = react_ruleset_inner(rc, mem, rs);
  }
  else {
    result = react_ruleset_atomic(rc, mem, rs);
  }

  return result;
}


/**  @see react_ruleset (task.c)  */
static inline BOOL react_ruleset_inner(LmnReactCxt *rc,
                                       LmnMembrane *mem,
                                       LmnRuleSet  rs)
{
  unsigned int i;
  BOOL ret = FALSE;
  for (i = 0; i < lmn_ruleset_rule_num(rs); i++) {
    LmnRule r = lmn_ruleset_get_rule(rs, i);
#ifdef PROFILE
    if (!lmn_env.nd && lmn_env.profile_level >= 2) {
      profile_rule_obj_set(rs, r);
    }
#endif
    if (react_rule(rc, mem, r)) {
      ret = TRUE;
      break;
    }
  }
  return ret;
}


/** 膜memに対してルールruleの適用を試みる.
 *  戻り値:
 *   通常実行では, 書換えに成功した場合にTRUE, マッチングしなかった場合にFALSEを返す.
 *   非決定実行では, マッチングに失敗するまでバックトラックを繰り返すため常にFALSEが返る. */
BOOL react_rule(LmnReactCxt *rc, LmnMembrane *mem, LmnRule rule)
{
  LmnTranslated translated;
  BYTE *inst_seq;
  BOOL result;

  translated = lmn_rule_get_translated(rule);
  inst_seq = lmn_rule_get_inst_seq(rule);

  wt_set(rc, 0, mem);
  tt_set(rc, 0, TT_MEM);
  warry_use_size_set(rc, 1);

  profile_start_trial();

  /* まず、トランスレート済みの関数を実行する
   * それがない場合、命令列をinterpretで実行する */
  result = (translated && translated(rc, mem, rule)) ||
           (inst_seq   && interpret(rc, rule, inst_seq));

  profile_finish_trial();

  if (RC_GET_MODE(rc, REACT_MEM_ORIENTED)) {
    if (lmn_env.trace && result) {
      if (lmn_env.sp_dump_format == LMN_SYNTAX) {
        lmn_dump_mem_stdout(RC_GROOT_MEM(rc));
        fprintf(stdout, ".\n");
        lmn_dump_mem_stdout(RC_GROOT_MEM(rc));
        fprintf(stdout, ":- ");
        RC_TRACE_NUM_INC(rc);
      } else if (lmn_env.output_format == JSON) {
        lmn_dump_cell_stdout(RC_GROOT_MEM(rc));
      } else {
        fprintf(stdout, "---->%s\n", lmn_id_to_name(lmn_rule_get_name(rule)));
        fprintf(stdout, "%d: ", RC_TRACE_NUM_INC(rc));
        lmn_dump_cell_stdout(RC_GROOT_MEM(rc));
        if (lmn_env.show_hyperlink) lmn_hyperlink_print(RC_GROOT_MEM(rc));
      }
    }
  }

  if (RC_HLINK_SPC(rc)) {
    lmn_sameproccxt_clear(rc); /* とりあえずここに配置 */
  }

  return result;
}


/* 膜memでrulesetsのルールの適用を行う.
 * 適用結果は無視する */
void react_start_rulesets(LmnMembrane *mem, Vector *rulesets)
{
  LmnReactCxt rc;
  int i;

  stand_alone_react_cxt_init(&rc);
  RC_SET_GROOT_MEM(&rc, mem);

  for (i = 0; i < vec_num(rulesets); i++) {
    react_ruleset(&rc, mem, (LmnRuleSet)vec_get(rulesets, i));
  }
  react_initial_rulesets(&rc, mem);
}


inline static void react_initial_rulesets(LmnReactCxt *rc, LmnMembrane *mem)
{
  int i;
  BOOL reacted;

  do {
    reacted = FALSE;
    if (react_ruleset_in_all_mem(rc, initial_system_ruleset, mem)) {
      reacted = TRUE;
      continue;
    }
    for (i = 0; i < lmn_ruleset_rule_num(initial_ruleset); i++) {
      if (react_rule(rc, mem, lmn_ruleset_get_rule(initial_ruleset, i))) {
        reacted = TRUE;
        break;
      }
    }
  } while (reacted);
}

/* ルールセットrsをmem以下のすべての膜内で適用する */
static BOOL react_ruleset_in_all_mem(LmnReactCxt *rc, LmnRuleSet rs, LmnMembrane *mem)
{
  LmnMembrane *m;

  for (m = mem->child_head; m; m = m->next) {
    if (react_ruleset_in_all_mem(rc, rs, m)) return TRUE;
  }

  return react_ruleset(rc, mem, rs);
}

/* Utility for reading data */

#define READ_DATA_ATOM(dest, attr)                            \
  do {                                                        \
    switch (attr) {                                           \
    case LMN_INT_ATTR:                                        \
      READ_VAL(long, instr, (dest));                          \
      break;                                                  \
    case LMN_DBL_ATTR:                                        \
    {                                                         \
      double *x;                                              \
      x = LMN_MALLOC(double);                                 \
      READ_VAL(double, instr, *x);                            \
      (dest) = (LmnWord)x;                                    \
      break;                                                  \
    }                                                         \
    case LMN_STRING_ATTR:                                     \
    {                                                         \
      lmn_interned_str s;                                     \
      READ_VAL(lmn_interned_str, instr, s);                   \
      (dest) = (LmnWord)lmn_string_make(lmn_id_to_name(s));   \
      break;                                                  \
    }                                                         \
    default:                                                  \
      lmn_fatal("Implementation error 1");                      \
    }                                                         \
  } while (0)

/* attrに応じて、ファンクタを読み込み、destに定数アトムを生成する。
 * attrは適切な値に変更する場合がある */
#define READ_CONST_DATA_ATOM(dest, attr, type)                \
  do {                                                        \
    switch (attr) {                                           \
    case LMN_INT_ATTR:                                        \
       READ_VAL(long, instr, (dest));                         \
       break;                                                 \
     case LMN_DBL_ATTR:                                       \
       (dest) = (LmnWord)instr;                               \
       instr += sizeof(double);                               \
       (attr) = LMN_CONST_DBL_ATTR;                           \
       break;                                                 \
     case LMN_STRING_ATTR:                                    \
     {                                                        \
        lmn_interned_str s;                                   \
        READ_VAL(lmn_interned_str, instr, s);                 \
        (dest) = s;                                           \
        (attr) = LMN_CONST_STR_ATTR;                          \
        break;                                                \
     }                                                        \
     default:                                                 \
        lmn_fatal("Implementation error 2");                    \
     }                                                        \
     (type) = TT_OTHER;                                       \
   } while (0)

#define READ_CMP_DATA_ATOM(attr, x, result, type)             \
  do {                                                        \
    switch(attr) {                                            \
    case LMN_INT_ATTR:                                        \
    {                                                         \
      long t;                                                 \
      READ_VAL(long, instr, t);                               \
      (result) = ((long)(x) == t);                            \
      break;                                                  \
    }                                                         \
    case LMN_DBL_ATTR:                                        \
    {                                                         \
      double t;                                               \
      READ_VAL(double, instr, t);                             \
      (result) = (*(double*)(x) == t);                        \
      break;                                                  \
    }                                                         \
    case LMN_STRING_ATTR:                                     \
    {                                                         \
      lmn_interned_str s;                                     \
      LmnString str1;                                         \
      READ_VAL(lmn_interned_str, instr, s);                   \
      str1 = lmn_string_make(lmn_id_to_name(s));              \
      (result) = lmn_string_eq(str1, (LmnString)(x));         \
      lmn_string_free(str1);                                  \
      break;                                                  \
    }                                                         \
    default:                                                  \
      lmn_fatal("Implementation error 3");                      \
    }                                                         \
    (type) = TT_ATOM;                                         \
  } while (0)

#define SKIP_DATA_ATOM(attr)                                  \
  do {                                                        \
    switch(attr) {                                            \
    case LMN_INT_ATTR:                                        \
    {                                                         \
      long t;                                                 \
      READ_VAL(long, instr, t);                               \
      break;                                                  \
    }                                                         \
    case LMN_DBL_ATTR:                                        \
    {                                                         \
      double t;                                               \
      READ_VAL(double, instr, t);                             \
      break;                                                  \
    }                                                         \
    case LMN_STRING_ATTR:                                     \
    {                                                         \
      lmn_interned_str s;                                     \
      READ_VAL(lmn_interned_str, instr, s);                   \
      break;                                                  \
    }                                                         \
    default:                                                  \
      lmn_fatal("Implementation error 4");                      \
    }                                                         \
  } while (0)

/* DEBUG: */
/* static void print_wt(void); */

/* mem != NULL ならば memにUNIFYを追加、そうでなければUNIFYは膜に所属しない */
HashSet *insertconnectors(LmnReactCxt *rc, LmnMembrane *mem, const Vector *links)
{
  unsigned int i, j;
  HashSet *retset;
  /* EFFICIENCY: retsetがHash Setである意味は?　ベクタでいいのでは？
   * 中間命令でセットを使うように書かれている */

  retset = hashset_make(8);
  for (i = 0; i < links->num; i++) {
    LmnWord linkid1 = vec_get(links, i);
    if (LMN_ATTR_IS_DATA(LINKED_ATTR(linkid1))) continue;
    for (j = i + 1; j < links->num; j++) {
      LmnWord linkid2 = vec_get(links, j);
      if (LMN_ATTR_IS_DATA(LINKED_ATTR(linkid2))) continue;
      /* is buddy? */
      if (LINKED_ATOM(linkid2) == LMN_SATOM_GET_LINK(LINKED_ATOM(linkid1), LINKED_ATTR(linkid1)) &&
          LINKED_ATTR(linkid2) == LMN_SATOM_GET_ATTR(LINKED_ATOM(linkid1), LINKED_ATTR(linkid1))) {
        /* '='アトムをはさむ */
        LmnSAtom eq;
        LmnSAtom a1, a2;
        LmnLinkAttr t1, t2;

        if (mem) eq = lmn_mem_newatom(mem, LMN_UNIFY_FUNCTOR);
        else {
          eq = lmn_new_atom(LMN_UNIFY_FUNCTOR);
        }

        if (LMN_SATOM_ID(eq) == 0) {
          LMN_SATOM_SET_ID(eq, env_gen_next_id());
        }

        /* リンクがリンクの元を持つ場合、あらかじめリンク先の取得をしていなければならない。
         * リンク元はnew_link時に書き換えられてしまう。*/

        a1 = LMN_SATOM(LINKED_ATOM(linkid1));
        a2 = LMN_SATOM(LINKED_ATOM(linkid2));
        t1 = LINKED_ATTR(linkid1);
        t2 = LINKED_ATTR(linkid2);

        lmn_newlink_in_symbols(a1, t1, eq, 0);
        lmn_newlink_in_symbols(a2, t2, eq, 1);
        hashset_add(retset, (HashKeyType)eq);
      }
    }
  }

  return retset;
}

static BOOL interpret(LmnReactCxt *rc, LmnRule rule, LmnRuleInstr instr)
{
  LmnInstrOp op;

  while (TRUE) {
  LOOP:;
    READ_VAL(LmnInstrOp, instr, op);

    switch (op) {
    case INSTR_SPEC:
    {
      LmnInstrVar s0, s1;

      READ_VAL(LmnInstrVar, instr, s0);
      READ_VAL(LmnInstrVar, instr, s1);

      if (s1 > warry_size(rc)) {
        lmn_register_extend(rc, s1);
      }
      warry_use_size_set(rc, s1);
      warry_cur_size_set(rc, 0);
      break;
    }
    case INSTR_INSERTCONNECTORSINNULL:
    {
      LmnInstrVar seti, list_num;
      Vector links;
      unsigned int i;

      READ_VAL(LmnInstrVar, instr, seti);
      READ_VAL(LmnInstrVar, instr, list_num);

      vec_init(&links, list_num + 1);
      for (i = 0; i < list_num; i++) {
        LmnInstrVar t;
        READ_VAL(LmnInstrVar, instr, t);
        vec_push(&links, (LmnWord)t);
      }

      warry_set(rc, seti, insertconnectors(rc, NULL, &links), 0, TT_OTHER);

      vec_destroy(&links);

      /* EFFICIENCY: 解放のための再帰 */
      if (interpret(rc, rule, instr)) {
        hashset_free((HashSet *)wt(rc, seti));
        return TRUE;
      } else {
        LMN_ASSERT(0);
      }

      break;
    }
    case INSTR_INSERTCONNECTORS:
    {
      LmnInstrVar seti, list_num, memi, enti;
      Vector links; /* src list */
      unsigned int i;

      READ_VAL(LmnInstrVar, instr, seti);
      READ_VAL(LmnInstrVar, instr, list_num);

      vec_init(&links, list_num + 1);

      for (i = 0; i < list_num; i++) {
        READ_VAL(LmnInstrVar, instr, enti);
        vec_push(&links, (LmnWord)enti);
      }

      READ_VAL(LmnInstrVar, instr, memi);
      warry_set(rc, seti,
                insertconnectors(rc, (LmnMembrane *)wt(rc, memi), &links),
                0,
                TT_OTHER);

      vec_destroy(&links);

      /* EFFICIENCY: 解放のための再帰 */
      if (interpret(rc, rule, instr)) {
        hashset_free((HashSet *)wt(rc, seti));
        return TRUE;
      } else {
        LMN_ASSERT(0);
      }
      break;
    }
    case INSTR_JUMP:
    {
      /* EFFICIENCY: 新たに作業配列をmallocしているので非常に遅い
                     -O3 で生成される中間命令にJUMPが含まれないため
                     これでもよい */
      LmnRegister *v, *tmp;
      LmnRuleInstr next;
      LmnInstrVar num, i, n;
      LmnJumpOffset offset;
      unsigned int warry_size_org, warry_use_org, warry_cur_org;
      BOOL ret;

      warry_size_org = warry_size(rc);
      warry_use_org  = warry_use_size(rc);
      warry_cur_org  = warry_cur_size(rc);
      v = lmn_register_make(warry_size_org);

      READ_VAL(LmnJumpOffset, instr, offset);
      next = instr + offset;

      i = 0;
      /* atom */
      READ_VAL(LmnInstrVar, instr, num);
      for (; num--; i++) {
        READ_VAL(LmnInstrVar, instr, n);
        v[i].wt = wt(rc, n);
        v[i].at = at(rc, n);
        v[i].tt = tt(rc, n);
      }
      /* mem */
      READ_VAL(LmnInstrVar, instr, num);
      for (; num--; i++) {
        READ_VAL(LmnInstrVar, instr, n);
        v[i].wt = wt(rc, n);
        v[i].at = at(rc, n);
        v[i].tt = tt(rc, n);
      }
      /* vars */
      READ_VAL(LmnInstrVar, instr, num);
      for (; num--; i++) {
        READ_VAL(LmnInstrVar, instr, n);
        v[i].wt = wt(rc, n);
        v[i].at = at(rc, n);
        v[i].tt = tt(rc, n);
      }

      instr = next;

      tmp   = rc_warry(rc);
      rc_warry_set(rc, v);

      ret = interpret(rc, rule, instr);

      lmn_register_free(rc_warry(rc));
      rc_warry_set(rc, tmp);
      warry_size_set(rc, warry_size_org);
      warry_use_size_set(rc, warry_use_org);
      warry_cur_size_set(rc, warry_cur_org);

      return ret;
    }
    case INSTR_RESETVARS:
    {
      LmnRegister *v;
      LmnInstrVar num, i, n, t;

      v = lmn_register_make(warry_use_size(rc));

      i = 0;
      /* atom */
      READ_VAL(LmnInstrVar, instr, num);
      for (; num--; i++) {
        READ_VAL(LmnInstrVar, instr, n);
        v[i].wt = wt(rc, n);
        v[i].at = at(rc, n);
        v[i].tt = tt(rc, n);
      }

      /* mem */
      READ_VAL(LmnInstrVar, instr, num);
      for (; num--; i++) {
        READ_VAL(LmnInstrVar, instr, n);
        v[i].wt = wt(rc, n);
        v[i].at = at(rc, n);
        v[i].tt = tt(rc, n);
      }

      /* vars */
      READ_VAL(LmnInstrVar, instr, num);
      for (; num--; i++) {
        READ_VAL(LmnInstrVar, instr, n);
        v[i].wt = wt(rc, n);
        v[i].at = at(rc, n);
        v[i].tt = tt(rc, n);
      }

      for (t = 0; t <= i; t++) {
        warry_set(rc, t, v[t].wt, v[t].at, v[t].tt);
      }

      lmn_register_free(v);
      break;
    }
    case INSTR_COMMIT:
    {
      lmn_interned_str rule_name;
      LmnLineNum       line_num;

      READ_VAL(lmn_interned_str, instr, rule_name);
      READ_VAL(LmnLineNum,       instr, line_num);

#ifdef KWBT_OPT
      {
        LmnInstrVar      cost;
        READ_VAL(LmnInstrVar,      instr, cost);
        lmn_rule_set_cost(rule, cost);
      }
#endif

      lmn_rule_set_name(rule, rule_name);

      profile_apply();

      /*
       * MC mode
       *
       * グローバル変数global_rootに格納されているグローバルルート膜をコピーして
       * そのコピーに対してボディ命令を適用する．
       * その際に変数配列の情報もコピー前のものからコピー後のものへと書き換える．
       *
       * CONTRACT: COMMIT命令に到達したルールはマッチング検査に成功している
       */
      if (RC_GET_MODE(rc, REACT_ND)) {
        ProcessID org_next_id = env_next_id();

        if (RC_MC_USE_DMEM(rc)) {
          /** >>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<< **/
          /** >>>>>>>> enable delta-membrane <<<<<<< **/
          /** >>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<< **/
          struct MemDeltaRoot *d;

          if (lmn_rule_get_pre_id(rule) != ANONYMOUS) {
            /* dmem_commit/revertとの整合性を保つため, uniq処理の特殊性を吸収しておく */
            LMN_ASSERT(lmn_rule_get_history_tbl(rule));
            st_delete(lmn_rule_get_history_tbl(rule), lmn_rule_get_pre_id(rule), 0);
          }

          d = dmem_root_make(RC_GROOT_MEM(rc), rule, env_next_id());
          RC_ND_SET_MEM_DELTA_ROOT(rc, d);

          if (lmn_rule_get_pre_id(rule) != ANONYMOUS) {
            lmn_rule_set_pre_id(rule, ANONYMOUS);
          }

          if (RC_MC_USE_DPOR(rc)) {
            dpor_transition_gen_LHS(RC_POR_DATA(rc), d, rc, rc_warry(rc));
          }

          dmem_interpret(rc, rule, instr);
          dmem_root_finish(d);

          if (RC_MC_USE_DPOR(rc)) {
            if (!dpor_transition_gen_RHS(RC_POR_DATA(rc), d, rc, rc_warry(rc))) {
              dmem_root_free(d);
            } else {
              mc_react_cxt_add_mem_delta(rc, d, rule);
            }

            /* サクセッサへの差分オブジェクトが複数できあがることになるが,
             * 差分オブジェクト間では生成したプロセスのIDに重複があってはならない. */
            RC_ND_SET_MEM_DELTA_ROOT(rc, NULL);
            return FALSE;
          }

          mc_react_cxt_add_mem_delta(rc, d, rule);
          RC_ND_SET_MEM_DELTA_ROOT(rc, NULL);
        }
        else {
          /** >>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<< **/
          /** >>>>>>> disable delta-membrane <<<<<<< **/
          /** >>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<< **/
          LmnRegister *v, *tmp;
          ProcessTbl copymap;
          LmnMembrane *tmp_global_root;
          unsigned int warry_size_org, warry_use_org, warry_cur_org;
          unsigned int i, n;

#ifdef PROFILE
          if (lmn_env.profile_level >= 3) {
            profile_start_timer(PROFILE_TIME__STATE_COPY_IN_COMMIT);
          }
#endif

          warry_size_org  = warry_size(rc);
          warry_use_org   = warry_use_size(rc);
          warry_cur_org   = warry_cur_size(rc);
          tmp_global_root = lmn_mem_copy_with_map_ex(RC_GROOT_MEM(rc), &copymap);

          /** 変数配列および属性配列のコピー */
          v = lmn_register_make(warry_size_org);

          if (warry_cur_org > 0) {
            /* -O3は, JUMP命令削除により, レジスタサイズはBODY命令込みの値になっているため,
             * 複数回のマッチングバックトラックが発生する場合に備え, COMMIT命令到達時点での
             * レジスタ使用サイズを使って, 作業配列をコピーするようにする. */
            n = warry_cur_org;
          } else {
            /* JUMP命令を使用する場合は, SPEC命令が複数呼び出される.
             * このため, O3用の変数cur_sizeはこの時点で0である.
             * SPECが指定したサイズで作業配列をコピーする. */
            n = warry_use_org;
          }

          /** copymapの情報を基に変数配列を書換える */
#ifdef TIME_OPT
          for (i = 0; i < n; i++) {
            LmnWord t;
            v[i].at = at(rc, i);
            v[i].tt = tt(rc, i);

            if (v[i].tt == TT_ATOM) {
              if (LMN_ATTR_IS_DATA(v[i].at)) {
                /* data-atom */
                if (v[i].at == LMN_HL_ATTR) {
                  if (proc_tbl_get_by_hlink(copymap, lmn_hyperlink_at_to_hl((LmnSAtom)wt(rc, i)), &t)) {
                    v[i].wt = (LmnWord)lmn_hyperlink_hl_to_at((HyperLink *)t);
                  } else {
                    v[i].wt = (LmnWord)wt(rc, i);/* new_hlink命令等の場合 */
                    //lmn_fatal("implementation error");
                  }
                } else {
                  v[i].wt = (LmnWord)lmn_copy_data_atom((LmnAtom)wt(rc, i), (LmnLinkAttr)v[i].at);
                }
              } else if (proc_tbl_get_by_atom(copymap, LMN_SATOM(wt(rc, i)), &t)) {
                /* symbol-atom */
                v[i].wt = (LmnWord)t;
              } else {
                t = 0;
                //lmn_fatal("implementation error");
              }
            }
            else if (v[i].tt == TT_MEM) {
              if (wt(rc, i) == (LmnWord)RC_GROOT_MEM(rc)) { /* グローバルルート膜 */
                v[i].wt = (LmnWord)tmp_global_root;
              } else if (proc_tbl_get_by_mem(copymap, (LmnMembrane *)wt(rc, i), &t)) {
                v[i].wt = (LmnWord)t;
              } else {
                t = 0;
                //lmn_fatal("implementation error");
              }
            }
            else { /* TT_OTHER */
              v[i].wt = wt(rc, i);
            }
          }
#else
          for (i = 0; i < warry_size_org; i++) {
            v[i].at = at(rc, i);
            if (LMN_ATTR_IS_DATA(v[i].at)) {
              if (v[i].at == LMN_HL_ATTR) {
                if (proc_tbl_get_by_hlink(copymap, lmn_hyperlink_at_to_hl(LMN_SATOM(wt(rc, i))), &t)) {
                  v[i].wt = (LmnWord)lmn_hyperlink_hl_to_at((HyperLink *)t);
                } else {
                  v[i].wt = (LmnWord)wt(rc, i);//new_hlink命令等の場合
                  //lmn_fatal("implementation error");
                }
              }
              v[i].wt = (LmnWord)lmn_copy_data_atom((LmnAtom)wt(rc, i), (LmnLinkAttr)v[i].at);
            }
            else if (proc_tbl_get(copymap, wt(rc, i), &t)) {
              v[i].wt = t;
            }
            else if(wt(rc, i) == (LmnWord)RC_GROOT_MEM(rc)) { /* グローバルルート膜 */
              v[i].wt = (LmnWord)tmp_global_root;
            }
          }
#endif
          proc_tbl_free(copymap);

          /** 変数配列および属性配列をコピーと入れ換え, コピー側を書き換える */
          tmp = rc_warry(rc);
          rc_warry_set(rc, v);

#ifdef PROFILE
          if (lmn_env.profile_level >= 3) {
            profile_finish_timer(PROFILE_TIME__STATE_COPY_IN_COMMIT);
          }
#endif

          /** コピーしたグローバルルート膜と作業配列を用いてBODY命令を適用  */
          interpret(rc, rule, instr);
          mc_react_cxt_add_expanded(rc, tmp_global_root, rule);

          if (lmn_rule_get_pre_id(rule) != ANONYMOUS) {
            LMN_ASSERT(lmn_rule_get_history_tbl(rule));
            st_delete(lmn_rule_get_history_tbl(rule), lmn_rule_get_pre_id(rule), 0);
            lmn_rule_set_pre_id(rule, ANONYMOUS);
          }

          /* 変数配列および属性配列を元に戻す */
          lmn_register_free(rc_warry(rc));
          rc_warry_set(rc, tmp);
          warry_size_set(rc, warry_size_org);
          warry_use_size_set(rc, warry_use_org);
          warry_cur_size_set(rc, warry_cur_org);
        }

        env_set_next_id(org_next_id);
        return FALSE; /* matching backtrack! */
      }
      else if (RC_GET_MODE(rc, REACT_PROPERTY)) {
        return TRUE;  /* propertyはmatchingのみ */
      }

      break;
    }
    case INSTR_FINDATOM:
    {
      LmnInstrVar atomi, memi;
      LmnLinkAttr attr;

      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnLinkAttr, instr, attr);

      if (LMN_ATTR_IS_DATA(attr)) {
        lmn_fatal("I can not find data atoms.\n");
      }
      else { /* symbol atom */
        LmnFunctor f;
        AtomListEntry *atomlist_ent;
        LmnSAtom atom;

        READ_VAL(LmnFunctor, instr, f);

        if (!rc_hlink_opt(atomi, rc)) { /* 通常はこっち */
          atomlist_ent = lmn_mem_get_atomlist((LmnMembrane*)wt(rc, memi), f);
          if (atomlist_ent) {
            EACH_ATOM(atom, atomlist_ent, ({
              warry_set(rc, atomi, atom, LMN_ATTR_MAKE_LINK(0), TT_ATOM);
              if (interpret(rc, rule, instr)) {
                return TRUE;
              }
              profile_backtrack();
            }));
          }
        }
        else { /* hyperlink の接続関係を利用したルールマッチング最適化 */
          SameProcCxt *spc;
          int atom_arity;

          if (!RC_HLINK_SPC(rc)) {
            lmn_sameproccxt_init(rc);
          }

          atom_arity = LMN_FUNCTOR_ARITY(f);

          /* 型付きプロセス文脈atomiがoriginal/cloneのどちらであるか判別 */
          spc = (SameProcCxt *)hashtbl_get(RC_HLINK_SPC(rc), (HashKeyType)atomi);
          if (lmn_sameproccxt_from_clone(spc, atom_arity)) {
            /** hyperlinkの接続関係からfindatom */
            int element_num;

            /* 探索の始点となるhyperlinkと同じ集合に含まれるhyperlink群を
             * (Vector*)LMN_SPC_TREE(spc)に取得.
             * (Vector*)LMN_SPC_TREE(spc)の最後に格納されているHyperLinkは
             * 探索の対象外なので要素数を-1する */
            lmn_hyperlink_get_elements(LMN_SPC_TREE(spc),
                                       lmn_sameproccxt_start(spc, atom_arity));
            element_num = vec_num(LMN_SPC_TREE(spc)) - 1;
            if (element_num <= 0) return FALSE;

            /* ----------------------------------------------------------
             * この時点で探索の始点とすべきハイパーリンクの情報がspc内に格納されている
             * ---------------------------------------------------------- */

            if (lmn_mem_get_atomlist((LmnMembrane *)wt(rc, memi), LMN_HL_FUNC)) {
              /* ハイパーリンクアトムが膜内にある場合 */
              int i;
              at_set(rc, atomi, LMN_ATTR_MAKE_LINK(0));
              tt_set(rc, atomi, TT_ATOM);
              for (i = 0; i < element_num; i++) {
                LmnSAtom linked_pc = ((HyperLink *)vec_get(LMN_SPC_TREE(spc), i))->atom;
                wt_set(rc, atomi, LMN_SATOM_GET_LINK(linked_pc, 0));
                /*    本来findatomするはずだったファンクタと一致しているか
                 * || hyperlinkアトムの接続先の引数が正しいか
                 * || 本来findatomするはずだったアトムと所属膜が一致しているか */
                if (LMN_SATOM_GET_FUNCTOR(wt(rc, atomi)) != f              ||
                    LMN_SPC_SATTR(spc) != LMN_SATOM_GET_ATTR(linked_pc, 0) ||
                    LMN_HL_MEM(lmn_hyperlink_at_to_hl(linked_pc)) !=
                        (LmnMembrane *)wt(rc, memi)) {
                  continue;
                }

                if (lmn_sameproccxt_all_pc_check_clone(spc,
                                                       LMN_SATOM(wt(rc, atomi)),
                                                       atom_arity) &&
                    interpret(rc, rule, instr)) {
                  return TRUE;
                }
                profile_backtrack();
              }
            }
          }
          else { /* 通常のfindatom */
            atomlist_ent = lmn_mem_get_atomlist((LmnMembrane*)wt(rc, memi), f);
            if (atomlist_ent) {
              EACH_ATOM(atom, atomlist_ent, ({
                warry_set(rc, atomi, atom, LMN_ATTR_MAKE_LINK(0), TT_ATOM);

                if (lmn_sameproccxt_all_pc_check_original(spc, atom, atom_arity) &&
                    interpret(rc, rule, instr)) {
                  return TRUE;
                }
                profile_backtrack();
              }));
            }
          }
        }
        return FALSE;
      }
      break;
    }
    case INSTR_FINDATOM2:
    {
      LmnInstrVar atomi, memi, findatomid;
      LmnLinkAttr attr;

      if (RC_GET_MODE(rc, REACT_ND)) {
        lmn_fatal("This mode:exhaustive search can't use instruction:FindAtom2");
      }

      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, findatomid);
      READ_VAL(LmnLinkAttr, instr, attr);
      if (LMN_ATTR_IS_DATA(attr)) {
        lmn_fatal("I can not find data atoms.\n");
      } else { /* symbol atom */
        LmnFunctor f;
        AtomListEntry *atomlist_ent;
        LmnSAtom start_atom, atom, record;

        READ_VAL(LmnFunctor, instr, f);
        atomlist_ent = lmn_mem_get_atomlist((LmnMembrane*)wt(rc, memi), f);
        if (atomlist_ent) {
          at_set(rc, atomi, LMN_ATTR_MAKE_LINK(0));
          tt_set(rc, atomi, TT_ATOM);

          record = LMN_SATOM(atomlist_get_record(atomlist_ent, findatomid));
          if (!record) {
            start_atom = atomlist_head(atomlist_ent);
            record = lmn_new_atom(LMN_RESUME_FUNCTOR);
            hashtbl_put(atomlist_ent->record, findatomid, (HashKeyType)record);
            /* 履歴アトムを挿入する */
            LMN_SATOM_SET_NEXT(atomlist_ent, record);
            LMN_SATOM_SET_PREV(record, atomlist_ent);
            LMN_SATOM_SET_NEXT(record, start_atom);
            LMN_SATOM_SET_PREV(start_atom, record);
          } else {
            start_atom = LMN_SATOM_GET_NEXT_RAW(record);
          }
#define DBG 0
#if DBG
          int count=0;
#endif
          for (atom = start_atom;
               atom != lmn_atomlist_end(atomlist_ent);
               atom = LMN_SATOM_GET_NEXT_RAW(atom)) {
#if DBG
            count++;
#endif
            if(LMN_SATOM_GET_FUNCTOR(atom) == LMN_RESUME_FUNCTOR)
              continue;
            wt_set(rc, atomi, atom);
            tt_set(rc, atomi, TT_ATOM);
            remove_from_atomlist(record, NULL);     /* 履歴アトムの削除 */
            insert_to_atomlist(NULL, record, atom, NULL); /* 履歴アトムの挿入 */

            if (interpret(rc, rule, instr)) {
#if DBG
              printf("count=%d\n", count);
#endif
              return TRUE;
            }
            profile_backtrack();
          }

          /* 現在のfindatom2の実装にはバグがある（cf. 言語班Wikifindatom2議論）。
           * バグを回避するために、履歴アトムの後ろのアトムすべてからのマッチングに失敗した場合、
           * 履歴アトムの前のアトムに対してマッチングを試みる */
          EACH_ATOM(atom, atomlist_ent, ({
            if (atom == start_atom) break;
            wt_set(rc, atomi, atom);
            tt_set(rc, atomi, TT_ATOM);
            if (interpret(rc, rule, instr)) {
              return TRUE;
            }
            profile_backtrack();
          }));

        }
        return FALSE;
      }
      break;
    }
    case INSTR_LOCKMEM:
    {
      LmnInstrVar memi, atomi, memn;
      LmnMembrane *m;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(lmn_interned_str, instr, memn);

      LMN_ASSERT(!LMN_ATTR_IS_DATA(at(rc, atomi)));
      LMN_ASSERT(LMN_IS_PROXY_FUNCTOR(LMN_SATOM_GET_FUNCTOR(LMN_SATOM(wt(rc, atomi)))));
//      LMN_ASSERT(((LmnMembrane *)wt(rc, memi))->parent);

      m = LMN_PROXY_GET_MEM(wt(rc, atomi));
      if (LMN_MEM_NAME_ID(m) != memn) return FALSE;
      warry_set(rc, memi, m, 0, TT_MEM);
      break;
    }
    case INSTR_ANYMEM:
    {
      LmnInstrVar mem1, mem2, memt, memn; /* dst, parent, type, name */
      LmnMembrane* mp;

      READ_VAL(LmnInstrVar, instr, mem1);
      READ_VAL(LmnInstrVar, instr, mem2);
      READ_VAL(LmnInstrVar, instr, memt);
      READ_VAL(lmn_interned_str, instr, memn);

      tt_set(rc, mem1, TT_MEM);
      mp = ((LmnMembrane*)wt(rc, mem2))->child_head;
      while (mp) {
        wt_set(rc, mem1, mp);
        at_set(rc, mem1, 0);
        if (mp->name == memn && interpret(rc, rule, instr)) {
          return TRUE;
        }
        mp = mp->next;
        profile_backtrack();
      }
      return FALSE;
      break;
    }
    case INSTR_NMEMS:
    {
      LmnInstrVar memi, nmems;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, nmems);

      if (!lmn_mem_nmems((LmnMembrane*)wt(rc, memi), nmems)) {
        return FALSE;
      }

      if (RC_GET_MODE(rc, REACT_ND) && RC_MC_USE_DPOR(rc)) {
        LmnMembrane *m = (LmnMembrane *)wt(rc, memi);
        dpor_LHS_flag_add(RC_POR_DATA(rc), lmn_mem_id(m), LHS_MEM_NMEMS);
        interpret(rc, rule, instr);
        dpor_LHS_flag_remove(RC_POR_DATA(rc), lmn_mem_id(m), LHS_MEM_NMEMS);
        return FALSE; /* 全ての候補取得のためにNDは常にFALSEを返す仕様 */
      }

      break;
    }
    case INSTR_NORULES:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      if(((LmnMembrane *)wt(rc, memi))->rulesets.num) return FALSE;

      if (RC_GET_MODE(rc, REACT_ND) && RC_MC_USE_DPOR(rc)) {
        LmnMembrane *m = (LmnMembrane *)wt(rc, memi);
        dpor_LHS_flag_add(RC_POR_DATA(rc), lmn_mem_id(m), LHS_MEM_NORULES);
        interpret(rc, rule, instr);
        dpor_LHS_flag_remove(RC_POR_DATA(rc), lmn_mem_id(m), LHS_MEM_NORULES);
        return FALSE; /* 全ての候補取得のためにNDは常にFALSEを返す仕様 */
      }

      break;
    }
    case INSTR_NEWATOM:
    {
      LmnInstrVar atomi, memi;
      LmnAtom ap;
      LmnLinkAttr attr;

      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnLinkAttr, instr, attr);
      if (LMN_ATTR_IS_DATA(attr)) {
        READ_DATA_ATOM(ap, attr);
      } else { /* symbol atom */
        LmnFunctor f;

        READ_VAL(LmnFunctor, instr, f);
        ap = LMN_ATOM(lmn_new_atom(f));
      }
      lmn_mem_push_atom((LmnMembrane *)wt(rc, memi), ap, attr);
      warry_set(rc, atomi, ap, attr, TT_ATOM);
      break;
    }
    case INSTR_NATOMS:
    {
      LmnInstrVar memi, natoms;
      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, natoms);

      if(!lmn_mem_natoms((LmnMembrane*)wt(rc, memi), natoms)) {
        return FALSE;
      }

      if (RC_GET_MODE(rc, REACT_ND) && RC_MC_USE_DPOR(rc)) {
        LmnMembrane *m = (LmnMembrane *)wt(rc, memi);
        dpor_LHS_flag_add(RC_POR_DATA(rc), lmn_mem_id(m), LHS_MEM_NATOMS);
        interpret(rc, rule, instr);
        dpor_LHS_flag_remove(RC_POR_DATA(rc), lmn_mem_id(m), LHS_MEM_NATOMS);
        return FALSE; /* 全ての候補取得のためにNDは常にFALSEを返す仕様 */
      }

      break;
    }
    case INSTR_NATOMSINDIRECT:
    {
      LmnInstrVar memi, natomsi;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, natomsi);

      if(!lmn_mem_natoms((LmnMembrane*)wt(rc, memi), wt(rc, natomsi))) {
        return FALSE;
      }

      if (RC_GET_MODE(rc, REACT_ND) && RC_MC_USE_DPOR(rc)) {
        LmnMembrane *m = (LmnMembrane *)wt(rc, memi);
        dpor_LHS_flag_add(RC_POR_DATA(rc), lmn_mem_id(m), LHS_MEM_NATOMS);
        interpret(rc, rule, instr);
        dpor_LHS_flag_remove(RC_POR_DATA(rc), lmn_mem_id(m), LHS_MEM_NATOMS);
        return FALSE; /* 全ての候補取得のためにNDは常にFALSEを返す仕様 */
      }


      break;
    }
    case INSTR_ALLOCLINK:
    {
      LmnInstrVar link, atom, n;

      READ_VAL(LmnInstrVar, instr, link);
      READ_VAL(LmnInstrVar, instr, atom);
      READ_VAL(LmnInstrVar, instr, n);

      if (LMN_ATTR_IS_DATA(at(rc, atom))) {
        warry_set(rc, link, wt(rc, atom), at(rc, atom), TT_ATOM);
      } else { /* link to atom */
        warry_set(rc, link, LMN_SATOM(wt(rc, atom)), LMN_ATTR_MAKE_LINK(n), TT_ATOM);
      }
      break;
    }
    case INSTR_UNIFYLINKS:
    {
      LmnInstrVar link1, link2, mem;
      LmnLinkAttr attr1, attr2;

      READ_VAL(LmnInstrVar, instr, link1);
      READ_VAL(LmnInstrVar, instr, link2);
      READ_VAL(LmnInstrVar, instr, mem);

      attr1 = LINKED_ATTR(link1);
      attr2 = LINKED_ATTR(link2);

      if (LMN_ATTR_IS_DATA_WITHOUT_EX(attr1)) {
        if (LMN_ATTR_IS_DATA_WITHOUT_EX(attr2)) { /* 1, 2 are data */
          lmn_mem_link_data_atoms((LmnMembrane *)wt(rc, mem),
                                  wt(rc, link1), at(rc, link1), LINKED_ATOM(link2), attr2);
        }
        else { /* 1 is data */
          LMN_SATOM_SET_LINK(LINKED_ATOM(link2), LMN_ATTR_GET_VALUE(attr2), LINKED_ATOM(link1));
          LMN_SATOM_SET_ATTR(LINKED_ATOM(link2), LMN_ATTR_GET_VALUE(attr2), attr1);
        }
      }
      else if (LMN_ATTR_IS_DATA_WITHOUT_EX(attr2)) { /* 2 is data */
        LMN_SATOM_SET_LINK(LINKED_ATOM(link1), LMN_ATTR_GET_VALUE(attr1), LINKED_ATOM(link2));
        LMN_SATOM_SET_ATTR(LINKED_ATOM(link1), LMN_ATTR_GET_VALUE(attr1), attr2);
      }
      else { /* 1, 2 are symbol atom */

        if (LMN_ATTR_IS_EX(attr1)) {
          if (LMN_ATTR_IS_EX(attr2)) { /* 1, 2 are ex */
            lmn_newlink_with_ex((LmnMembrane *)wt(rc, mem),
                                LMN_SATOM(LINKED_ATOM(link1)), attr1, 0, // ex atom ⊂ unary atom
                                LMN_SATOM(LINKED_ATOM(link2)), attr2, 0);
          } else { /* 1 is ex */
            lmn_newlink_with_ex((LmnMembrane *)wt(rc, mem),
                                LMN_SATOM(LINKED_ATOM(link1)), attr1, 0,
                                LMN_SATOM(LINKED_ATOM(link2)), attr2, attr2);
          }
        } else if (LMN_ATTR_IS_EX(attr2)) { /* 2 is ex */
          lmn_newlink_with_ex((LmnMembrane *)wt(rc, mem),
                              LMN_SATOM(LINKED_ATOM(link1)), attr1, attr1,
                              LMN_SATOM(LINKED_ATOM(link2)), attr2, 0);
        } else {
          LMN_SATOM_SET_LINK(LINKED_ATOM(link1), LMN_ATTR_GET_VALUE(attr1), LINKED_ATOM(link2));
          LMN_SATOM_SET_LINK(LINKED_ATOM(link2), LMN_ATTR_GET_VALUE(attr2), LINKED_ATOM(link1));
          LMN_SATOM_SET_ATTR(LINKED_ATOM(link1), LMN_ATTR_GET_VALUE(attr1), attr2);
          LMN_SATOM_SET_ATTR(LINKED_ATOM(link2), LMN_ATTR_GET_VALUE(attr2), attr1);
        }

      }
      break;
    }
    case INSTR_NEWLINK:
    {
      LmnInstrVar atom1, atom2, pos1, pos2, memi;

      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, pos1);
      READ_VAL(LmnInstrVar, instr, atom2);
      READ_VAL(LmnInstrVar, instr, pos2);
      READ_VAL(LmnInstrVar, instr, memi);

      lmn_mem_newlink((LmnMembrane *)wt(rc, memi),
                      wt(rc, atom1), at(rc, atom1), pos1,
                      wt(rc, atom2), at(rc, atom2), pos2);
      break;
    }
    case INSTR_RELINK:
    {
      LmnInstrVar atom1, atom2, pos1, pos2, memi;
      LmnSAtom ap;
      LmnByte attr;

      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, pos1);
      READ_VAL(LmnInstrVar, instr, atom2);
      READ_VAL(LmnInstrVar, instr, pos2);
      READ_VAL(LmnInstrVar, instr, memi);

      ap = LMN_SATOM(LMN_SATOM_GET_LINK(wt(rc, atom2), pos2));
      attr = LMN_SATOM_GET_ATTR(wt(rc, atom2), pos2);

      if (LMN_ATTR_IS_DATA_WITHOUT_EX(at(rc, atom1)) && LMN_ATTR_IS_DATA_WITHOUT_EX(attr)) {
        /* hlink属性ではない通常のデータアトム同士の接続 */
#ifdef DEBUG
        fprintf(stderr, "Two data atoms are connected each other.\n");
#endif
      }
      else if (LMN_ATTR_IS_DATA_WITHOUT_EX(at(rc, atom1))) {
        /* hlink属性ではない通常のデータアトムatom1とシンボルアトムatom2の接続.  */
        LMN_SATOM_SET_LINK(ap, attr, wt(rc, atom1));
        LMN_SATOM_SET_ATTR(ap, attr, at(rc, atom1));
      }
      else if (LMN_ATTR_IS_DATA_WITHOUT_EX(attr)) {
        /* hlink属性ではない通常のデータアトムatom2とシンボルアトムatom1の接続 */
        LMN_SATOM_SET_LINK(LMN_SATOM(wt(rc, atom1)), pos1, ap);
        LMN_SATOM_SET_ATTR(LMN_SATOM(wt(rc, atom1)), pos1, attr);
      }
      else if (!LMN_ATTR_IS_EX(at(rc, atom1)) && !LMN_ATTR_IS_EX(attr)) {
        /* シンボルアトム同士の接続 */
        LMN_SATOM_SET_LINK(ap, attr, wt(rc, atom1));
        LMN_SATOM_SET_ATTR(ap, attr, pos1);
        LMN_SATOM_SET_LINK(LMN_SATOM(wt(rc, atom1)), pos1, ap);
        LMN_SATOM_SET_ATTR(LMN_SATOM(wt(rc, atom1)), pos1, attr);
      } else if (LMN_ATTR_IS_EX(at(rc, atom1))) {
        lmn_newlink_with_ex((LmnMembrane *)wt(rc, memi),
                            LMN_SATOM(wt(rc, atom1)),
                            at(rc, atom1),
                            pos1,
                            ap,
			    // 0,
			    attr, /* this arg should be attr because  
				     atom2 may be a hyperlink. */ 
                            attr);
      } else {
        lmn_newlink_with_ex((LmnMembrane *)wt(rc, memi),
                            LMN_SATOM(wt(rc, atom1)),
                            at(rc, atom1),
                            pos1,
                            ap,
                            attr,
                            0);
      }
      break;
    }
    case INSTR_SWAPLINK:
    {
      LmnInstrVar atom1, atom2, pos1, pos2;
      LmnSAtom ap1,ap2;
      LmnLinkAttr attr1, attr2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, pos1);
      READ_VAL(LmnInstrVar, instr, atom2);
      READ_VAL(LmnInstrVar, instr, pos2);
      ap1 = LMN_SATOM(LMN_SATOM_GET_LINK(wt(rc, atom1), pos1));
      ap2 = LMN_SATOM(LMN_SATOM_GET_LINK(wt(rc, atom2), pos2));
      attr1 = LMN_SATOM_GET_ATTR(wt(rc, atom1), pos1);
      attr2 = LMN_SATOM_GET_ATTR(wt(rc, atom2), pos2);
      if ((LMN_ATTR_IS_DATA_WITHOUT_EX(at(rc, atom1)) && LMN_ATTR_IS_DATA_WITHOUT_EX(attr2))
          || (LMN_ATTR_IS_DATA_WITHOUT_EX(at(rc, atom2)) && LMN_ATTR_IS_DATA_WITHOUT_EX(attr1))) {
        /* atom1とap2が共にデータアトム or atom2とap1が共にデータアトム */
#ifdef DEBUG
        fprintf(stderr, "Two data atoms are connected each other.\n");
#endif
      }
      else if (LMN_ATTR_IS_DATA_WITHOUT_EX(at(rc, atom2))){
        /* データアトムatom2とシンボルアトムap1 */
        LMN_SATOM_SET_LINK(ap1, attr1, wt(rc, atom2));
        LMN_SATOM_SET_ATTR(ap1, attr1, at(rc, atom2));
        if (LMN_ATTR_IS_DATA_WITHOUT_EX(at(rc, atom1))){
          /* データアトムatom1とシンボルアトムap2 */
          LMN_SATOM_SET_LINK(ap2, attr2, wt(rc, atom1));
          LMN_SATOM_SET_ATTR(ap2, attr2, at(rc, atom1));
        }else if (LMN_ATTR_IS_DATA_WITHOUT_EX(attr2)){
          /* データアトムap2とシンボルアトムatom1 */
          LMN_SATOM_SET_LINK(LMN_SATOM(wt(rc, atom1)), pos1, ap2);
          LMN_SATOM_SET_ATTR(LMN_SATOM(wt(rc, atom1)), pos1, attr2);
        }else {
          /* シンボルアトムatom1とシンボルアトムap2 */
          LMN_SATOM_SET_LINK(ap2, attr2, wt(rc, atom1));
          LMN_SATOM_SET_ATTR(ap2, attr2, at(rc, atom1));
          LMN_SATOM_SET_LINK(LMN_SATOM(wt(rc, atom1)), pos1, ap2);
          LMN_SATOM_SET_ATTR(LMN_SATOM(wt(rc, atom1)), pos1, attr2);
        }
      }
      else if (LMN_ATTR_IS_DATA_WITHOUT_EX(attr1)){
        /* データアトムap1とシンボルアトムatom2 */
        LMN_SATOM_SET_LINK(LMN_SATOM(wt(rc, atom2)), pos2, ap1);
        LMN_SATOM_SET_ATTR(LMN_SATOM(wt(rc, atom2)), pos2, attr1);
        if (LMN_ATTR_IS_DATA_WITHOUT_EX(at(rc, atom1))){
          /* データアトムatom1とシンボルアトムap2 */
          LMN_SATOM_SET_LINK(ap2, attr2, wt(rc, atom1));
          LMN_SATOM_SET_ATTR(ap2, attr2, at(rc, atom1));
        }else if (LMN_ATTR_IS_DATA_WITHOUT_EX(attr2)){
          /* データアトムap2とシンボルアトムatom1 */
          LMN_SATOM_SET_LINK(LMN_SATOM(wt(rc, atom1)), pos1, ap2);
          LMN_SATOM_SET_ATTR(LMN_SATOM(wt(rc, atom1)), pos1, attr2);
        }else if (!LMN_ATTR_IS_EX(at(rc, atom1)) && !LMN_ATTR_IS_EX(attr2)){
          /* シンボルアトムatom1とシンボルアトムap2 */
          LMN_SATOM_SET_LINK(ap2, attr2, wt(rc, atom1));
          LMN_SATOM_SET_ATTR(ap2, attr2, at(rc, atom1));
          LMN_SATOM_SET_LINK(LMN_SATOM(wt(rc, atom1)), pos1, ap2);
          LMN_SATOM_SET_ATTR(LMN_SATOM(wt(rc, atom1)), pos1, attr2);
        }
      }
      else if (!LMN_ATTR_IS_EX(at(rc, atom1)) && !LMN_ATTR_IS_EX(at(rc, atom2))
               && !LMN_ATTR_IS_EX(attr1) && !LMN_ATTR_IS_EX(attr2)){
        /* シンボルアトムatom2とシンボルアトムap1 */

        if(ap1){
          LMN_SATOM_SET_LINK(LMN_SATOM(wt(rc, atom2)), pos2, ap1);
          LMN_SATOM_SET_ATTR(LMN_SATOM(wt(rc, atom2)), pos2, attr1);
          LMN_SATOM_SET_LINK(ap1, attr1, wt(rc, atom2));
          LMN_SATOM_SET_ATTR(ap1, attr1, pos2);
        }else{
          LMN_SATOM_SET_LINK(LMN_SATOM(wt(rc, atom2)), pos2, 0);
          LMN_SATOM_SET_ATTR(LMN_SATOM(wt(rc, atom2)), pos2, 0);
        }
        if(ap2){
        if(LMN_ATTR_IS_DATA_WITHOUT_EX(at(rc, atom1))){
          /* データアトムatom1とシンボルアトムap2 */
          LMN_SATOM_SET_LINK(ap2, attr2, wt(rc, atom1));
          LMN_SATOM_SET_ATTR(ap2, attr2, at(rc, atom1));
        }else if(LMN_ATTR_IS_DATA_WITHOUT_EX(attr2)){
          /* データアトムap2とシンボルアトムatom1 */
          LMN_SATOM_SET_LINK(LMN_SATOM(wt(rc, atom1)), pos1, ap2);
          LMN_SATOM_SET_ATTR(LMN_SATOM(wt(rc, atom1)), pos1, attr2);
        }else{
          /* シンボルアトムatom1とシンボルアトムap2 */
          LMN_SATOM_SET_LINK(ap2, attr2, wt(rc, atom1));
          LMN_SATOM_SET_ATTR(ap2, attr2, pos1);
          LMN_SATOM_SET_LINK(LMN_SATOM(wt(rc, atom1)), pos1, ap2);
          LMN_SATOM_SET_ATTR(LMN_SATOM(wt(rc, atom1)), pos1, attr2);
        }
        }else{
          LMN_SATOM_SET_LINK(LMN_SATOM(wt(rc, atom1)), pos1, 0);
          LMN_SATOM_SET_ATTR(LMN_SATOM(wt(rc, atom1)), pos1,0);
          }
      }
      break;
    }
    case INSTR_INHERITLINK:
    {
      LmnInstrVar atomi, posi, linki, memi;
      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnInstrVar, instr, posi);
      READ_VAL(LmnInstrVar, instr, linki);
      READ_VAL(LmnInstrVar, instr, memi);

      if (LMN_ATTR_IS_DATA(at(rc, atomi)) && LMN_ATTR_IS_DATA(LINKED_ATTR(linki))) {
#ifdef DEBUG
        fprintf(stderr, "Two data atoms are connected each other.\n");
#endif
      }
      else if(LMN_ATTR_IS_DATA(at(rc, atomi))) {
        LMN_SATOM_SET_LINK(LINKED_ATOM(linki), LINKED_ATTR(linki), wt(rc, atomi));
        LMN_SATOM_SET_ATTR(LINKED_ATOM(linki), LINKED_ATTR(linki), at(rc, atomi));
      }
      else if(LMN_ATTR_IS_DATA(LINKED_ATTR(linki))) {
        LMN_SATOM_SET_LINK(LMN_SATOM(wt(rc, atomi)), posi, LINKED_ATOM(linki));
        LMN_SATOM_SET_ATTR(LMN_SATOM(wt(rc, atomi)), posi, LINKED_ATTR(linki));
      }
      else {
        LMN_SATOM_SET_LINK(LMN_SATOM(wt(rc, atomi)), posi, LINKED_ATOM(linki));
        LMN_SATOM_SET_ATTR(LMN_SATOM(wt(rc, atomi)), posi, LINKED_ATTR(linki));
        LMN_SATOM_SET_LINK(LINKED_ATOM(linki), LINKED_ATTR(linki), wt(rc, atomi));
        LMN_SATOM_SET_ATTR(LINKED_ATOM(linki), LINKED_ATTR(linki), posi);
      }

      break;
    }
    case INSTR_GETLINK:
    {
      LmnInstrVar linki, atomi, posi;
      READ_VAL(LmnInstrVar, instr, linki);
      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnInstrVar, instr, posi);

      /* リンク先の取得をせずにリンク元の情報を格納しておく。
       * リンク元が格納されていることを示すため最下位のビットを立てる */
      warry_set(rc, linki,
                LMN_SATOM_GET_LINK(wt(rc, atomi), posi),
                LMN_SATOM_GET_ATTR(wt(rc, atomi), posi),
                TT_ATOM);

      break;
    }
    case INSTR_HYPERGETLINK:
    //head部用命令
    //hyperlinkにつながるリンク先だけレジスタに格納かつ以降の命令の実行を行う
    {
      LmnInstrVar linki, atomi, posi;
      READ_VAL(LmnInstrVar, instr, linki);
      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnInstrVar, instr, posi);

      LmnAtom hlAtom = LMN_SATOM_GET_LINK(wt(rc, atomi), posi);
      LmnLinkAttr attr = LMN_SATOM_GET_ATTR(wt(rc, atomi), posi);
      if (attr != LMN_HL_ATTR) {
        return FALSE;
      } else {
        HyperLink *hl = lmn_hyperlink_at_to_hl(LMN_SATOM(hlAtom));
        Vector hl_childs;
        vec_init(&hl_childs, 16);
        int element_num, i;
        lmn_hyperlink_get_elements(&hl_childs, hl);
        element_num = vec_num(&hl_childs) - 1;
        for (i = 0; i < element_num; i++) {
          LmnSAtom child_hlAtom = ((HyperLink *)vec_get(&hl_childs, i))->atom;
          LmnAtom linked_atom = LMN_SATOM_GET_LINK(child_hlAtom, 0);

          warry_set(rc, linki,
              linked_atom,
              LMN_SATOM_GET_ATTR(child_hlAtom, 0),
              TT_ATOM);

          if(interpret(rc, rule, instr)) {
            return TRUE;
          }
          profile_backtrack();
        }
        vec_destroy(&hl_childs);
      }
      break;
    }
    case INSTR_UNIFY:
    {
      LmnInstrVar atom1, pos1, atom2, pos2, memi;

      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, pos1);
      READ_VAL(LmnInstrVar, instr, atom2);
      READ_VAL(LmnInstrVar, instr, pos2);
      READ_VAL(LmnInstrVar, instr, memi);

      lmn_mem_unify_atom_args((LmnMembrane *)wt(rc, memi),
                              LMN_SATOM(wt(rc, atom1)), pos1,
                              LMN_SATOM(wt(rc, atom2)), pos2);
      break;
    }
    case INSTR_PROCEED:
      return TRUE;
    case INSTR_STOP:
      return FALSE;
    case INSTR_NOT:
    {
      LmnSubInstrSize subinstr_size;
      READ_VAL(LmnSubInstrSize, instr, subinstr_size);

      if (interpret(rc, rule, instr)) {
        return FALSE;
      }
      instr += subinstr_size;
      break;
    }
    case INSTR_ENQUEUEATOM:
    {
      LmnInstrVar atom;

      READ_VAL(LmnInstrVar, instr, atom);
      /* do nothing */
      break;
    }
    case INSTR_DEQUEUEATOM:
    {
      LmnInstrVar atom;

      READ_VAL(LmnInstrVar, instr, atom);
      break;
    }
    case INSTR_TAILATOM:
      {
        LmnInstrVar atomi, memi;

        READ_VAL(LmnInstrVar, instr, atomi);
        READ_VAL(LmnInstrVar, instr, memi);
        move_atom_to_atomlist_tail(wt(rc,atomi),(LmnMembrane *)wt(rc,memi));
        break;
      }

    case INSTR_HEADATOM:
      {
        LmnInstrVar atomi, memi;

        READ_VAL(LmnInstrVar, instr, atomi);
        READ_VAL(LmnInstrVar, instr, memi);
        move_atom_to_atomlist_head(wt(rc,atomi),(LmnMembrane *)wt(rc,memi));
        break;
      }
    case INSTR_NEWMEM:
    {
      LmnInstrVar newmemi, parentmemi, memf;
      LmnMembrane *mp;

      READ_VAL(LmnInstrVar, instr, newmemi);
      READ_VAL(LmnInstrVar, instr, parentmemi);
      READ_VAL(LmnInstrVar, instr, memf);

      mp = lmn_mem_make(); /*lmn_new_mem(memf);*/
      lmn_mem_add_child_mem((LmnMembrane*)wt(rc, parentmemi), mp);
      wt_set(rc, newmemi, mp);
      tt_set(rc, newmemi, TT_MEM);
      lmn_mem_set_active(mp, TRUE);
      if (RC_GET_MODE(rc, REACT_MEM_ORIENTED)) {
        lmn_memstack_push(RC_MEMSTACK(rc), mp);
      }
      break;
    }
    case INSTR_ALLOCMEM:
    {
      LmnInstrVar dstmemi;
      READ_VAL(LmnInstrVar, instr, dstmemi);
      wt_set(rc, dstmemi, lmn_mem_make());
      break;
    }
    case INSTR_REMOVEATOM:
    {
      LmnInstrVar atomi, memi;

      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnInstrVar, instr, memi);
      lmn_mem_remove_atom((LmnMembrane *)wt(rc, memi),
                          wt(rc, atomi),
                          at(rc, atomi));

      break;
    }
    case INSTR_FREEATOM:
    {
      LmnInstrVar atomi;

      READ_VAL(LmnInstrVar, instr, atomi);
      lmn_free_atom(wt(rc, atomi), at(rc, atomi));
      break;
    }
    case INSTR_REMOVEMEM:
    {
      LmnInstrVar memi, parenti;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, parenti);

      lmn_mem_remove_mem((LmnMembrane *)wt(rc, parenti),
                         (LmnMembrane *)wt(rc, memi));
      break;
    }
    case INSTR_FREEMEM:
    {
      LmnInstrVar memi;
      LmnMembrane *mp;

      READ_VAL(LmnInstrVar, instr, memi);

      mp = (LmnMembrane*)wt(rc, memi);
      lmn_mem_free(mp);
      break;
    }
    case INSTR_ADDMEM:
    {
      LmnInstrVar dstmem, srcmem;

      READ_VAL(LmnInstrVar, instr, dstmem);
      READ_VAL(LmnInstrVar, instr, srcmem);

//      LMN_ASSERT(!((LmnMembrane *)wt(rc, srcmem))->parent);

      lmn_mem_add_child_mem((LmnMembrane *)wt(rc, dstmem),
                            (LmnMembrane *)wt(rc, srcmem));
      break;
    }
    case INSTR_ENQUEUEMEM:
    {
      LmnInstrVar memi;
      READ_VAL(LmnInstrVar, instr, memi);
//      if (RC_GET_MODE(rc, REACT_ND)) {
//        lmn_mem_activate_ancestors((LmnMembrane *)wt(rc, memi)); /* MC */
//      }
//      else
      if (RC_GET_MODE(rc, REACT_MEM_ORIENTED)) {
        lmn_memstack_push(RC_MEMSTACK(rc), (LmnMembrane *)wt(rc, memi));
      }
      break;
    }
    case INSTR_UNLOCKMEM:
    { /* 何もしない */
      LmnInstrVar memi;
      READ_VAL(LmnInstrVar, instr, memi);
      break;
    }
    case INSTR_LOADRULESET:
    {
      LmnInstrVar memi;
      LmnRulesetId id;
      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnRulesetId, instr, id);

      lmn_mem_add_ruleset((LmnMembrane *)wt(rc, memi), lmn_ruleset_from_id(id));
      break;
    }
    case INSTR_LOADMODULE:
    {
      LmnInstrVar memi;
      lmn_interned_str module_name_id;
      LmnRuleSet ruleset;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(lmn_interned_str, instr, module_name_id);

      if ((ruleset = lmn_get_module_ruleset(module_name_id))) {
        /* テーブル内にルールセットがある場合 */
        lmn_mem_add_ruleset((LmnMembrane*)wt(rc, memi), ruleset);
      }
      else {
        /* テーブル内にルールセットがない場合 */
        fprintf(stderr, "Undefined module %s\n", lmn_id_to_name(module_name_id));
      }
      break;
    }
    case INSTR_RECURSIVELOCK:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      /* do notiong */
      break;
    }
    case INSTR_RECURSIVEUNLOCK:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      /* do notiong */
      break;
    }
    case INSTR_DEREFATOM:
    {
      LmnInstrVar atom1, atom2, posi;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);
      READ_VAL(LmnInstrVar, instr, posi);

      warry_set(rc, atom1,
                LMN_SATOM(LMN_SATOM_GET_LINK(wt(rc, atom2), posi)),
                LMN_SATOM_GET_ATTR(wt(rc, atom2), posi),
                TT_ATOM);
      break;
    }
    case INSTR_DEREF:
    {
      LmnInstrVar atom1, atom2, pos1, pos2;
      LmnByte attr;

      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);
      READ_VAL(LmnInstrVar, instr, pos1);
      READ_VAL(LmnInstrVar, instr, pos2);

      attr = LMN_SATOM_GET_ATTR(wt(rc, atom2), pos1);
      LMN_ASSERT(!LMN_ATTR_IS_DATA(at(rc, atom2)));
      if (LMN_ATTR_IS_DATA(attr)) {
        if (pos2 != 0) return FALSE;
      }
      else {
        if (attr != pos2) return FALSE;
      }
      warry_set(rc, atom1,
                LMN_SATOM_GET_LINK(wt(rc, atom2), pos1),
                attr,
                TT_ATOM);
      break;
    }
    case INSTR_FUNC:
    {
      LmnInstrVar atomi;
      LmnFunctor f;
      LmnLinkAttr attr;
      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnLinkAttr, instr, attr);

      if (LMN_ATTR_IS_DATA(at(rc, atomi)) == LMN_ATTR_IS_DATA(attr)) {
        if(LMN_ATTR_IS_DATA(at(rc, atomi))) {
          BOOL eq;
          if(at(rc, atomi) != attr) return FALSE; /* comp attr */
          READ_CMP_DATA_ATOM(attr, wt(rc, atomi), eq, tt(rc, atomi));
          if (!eq) return FALSE;
        }
        else {/* symbol atom */
          READ_VAL(LmnFunctor, instr, f);
          if (LMN_SATOM_GET_FUNCTOR(LMN_SATOM(wt(rc, atomi))) != f) {
            return FALSE;
          }
          if (rc_hlink_opt(atomi, rc) &&
              !lmn_sameproccxt_all_pc_check_original((SameProcCxt *)hashtbl_get(RC_HLINK_SPC(rc), (HashKeyType)atomi),
                                                     LMN_SATOM(wt(rc, atomi)),
                                                     LMN_FUNCTOR_ARITY(f)))
            return FALSE;
        }
      }
      else { /* LMN_ATTR_IS_DATA(at(rc, atomi)) != LMN_ATTR_IS_DATA(attr) */
        return FALSE;
      }
      break;
    }
    case INSTR_NOTFUNC:
    {
      LmnInstrVar atomi;
      LmnFunctor f;
      LmnLinkAttr attr;
      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnLinkAttr, instr, attr);

      if (LMN_ATTR_IS_DATA(at(rc, atomi)) == LMN_ATTR_IS_DATA(attr)) {
        if (LMN_ATTR_IS_DATA(at(rc, atomi))) {
          if (at(rc, atomi) == attr) {
            BOOL eq;
            READ_CMP_DATA_ATOM(attr, wt(rc, atomi), eq, tt(rc, atomi));
            if (eq) return FALSE;
          } else {
            goto label_skip_data_atom;
          }
        }
        else { /* symbol atom */
          READ_VAL(LmnFunctor, instr, f);
          if (LMN_SATOM_GET_FUNCTOR(LMN_SATOM(wt(rc, atomi))) == f) return FALSE;
        }
      } else if(LMN_ATTR_IS_DATA(attr)) {
        goto label_skip_data_atom;
      }
      break;
label_skip_data_atom:
      SKIP_DATA_ATOM(attr);
      break;
    }
    case INSTR_ISGROUND:
    case INSTR_ISHLGROUND:
    case INSTR_ISHLGROUNDINDIRECT:
    {
      LmnInstrVar funci, srclisti, avolisti;
      Vector *srcvec, *avovec;
      unsigned long natoms;
      BOOL b;

      READ_VAL(LmnInstrVar, instr, funci);
      READ_VAL(LmnInstrVar, instr, srclisti);
      READ_VAL(LmnInstrVar, instr, avolisti);

      /* リンクオブジェクトのベクタを構築 */
      srcvec = links_from_idxs((Vector *)wt(rc, srclisti), rc_warry(rc));
      avovec = links_from_idxs((Vector *)wt(rc, avolisti), rc_warry(rc));

      if (RC_GET_MODE(rc, REACT_ND) && RC_MC_USE_DPOR(rc)) {
        ProcessTbl atoms;
        ProcessTbl hlinks;
        hlinks = NULL;
        switch (op) {
        case INSTR_ISHLGROUND:
        case INSTR_ISHLGROUNDINDIRECT:
        {
          ProcessTbl attr_functors;
          Vector attr_dataAtoms;
          Vector attr_dataAtom_attrs;
            vec_init(&attr_dataAtoms, 16);
            vec_init(&attr_dataAtom_attrs, 16);
            attr_functors = proc_tbl_make_with_size(16);
            LmnInstrVar i = 0, n;

            READ_VAL(LmnInstrVar, instr, n);
            switch (op) {
            case INSTR_ISHLGROUNDINDIRECT:
              {
                LmnInstrVar ai;
                for (; n--; i++) {
                  READ_VAL(LmnInstrVar, instr, ai);
                  if (LMN_ATTR_IS_DATA(at(rc, ai))) {
                    vec_push(&attr_dataAtom_attrs, at(rc, ai));
                    vec_push(&attr_dataAtoms, ai);
                  } else {
                    LmnFunctor f;
                    f = LMN_SATOM_GET_FUNCTOR(wt(rc, ai));
                    proc_tbl_put(attr_functors, f, f);
                  }
                }
                break;
              }
            case INSTR_ISHLGROUND:
              {
                for (; n--; i++) {
                  LmnLinkAttr attr;
                  READ_VAL(LmnLinkAttr, instr, attr);
                  if (LMN_ATTR_IS_DATA(attr)) {
                    LmnAtom at;
                    vec_push(&attr_dataAtom_attrs, attr);
                    READ_DATA_ATOM(at, attr);
                    vec_push(&attr_dataAtoms, at);
                  } else {
                    LmnFunctor f;
                    READ_VAL(LmnFunctor, instr, f);
                    proc_tbl_put(attr_functors, f, f);
                  }
                }
                break;
              }
            }
            b = ground_atoms(srcvec,
                              avovec,
                              &atoms,
                              &natoms,
                              &hlinks,
                              &attr_functors,
                              &attr_dataAtoms,
                              &attr_dataAtom_attrs);
            proc_tbl_free(attr_functors);
            vec_destroy(&attr_dataAtoms);
            vec_destroy(&attr_dataAtom_attrs);
            break;
          }
        case INSTR_ISGROUND:
          {
            b = ground_atoms(srcvec, avovec, &atoms, &natoms, NULL, NULL, NULL, NULL);
            break;
          }
        }
        free_links(srcvec);
        free_links(avovec);

        if (b) {
          /* proc_tblを登録 */
          dpor_LHS_add_ground_atoms(RC_POR_DATA(rc), atoms);
          warry_set(rc, funci, natoms, LMN_INT_ATTR, TT_OTHER);

          interpret(rc, rule, instr); /* 開放のための再帰 */

          /* proc_tblを取り除く */
          dpor_LHS_remove_ground_atoms(RC_POR_DATA(rc), atoms);
          proc_tbl_free(atoms);
          proc_tbl_free(hlinks);
        }

        return FALSE; /* 全ての候補取得のためにNDは常にFALSEを返す仕様 */
      }
      else {
        switch (op) {
          case INSTR_ISHLGROUND:
          case INSTR_ISHLGROUNDINDIRECT:
          {
            ProcessTbl attr_functors;
            Vector attr_dataAtoms;
            Vector attr_dataAtom_attrs;
            vec_init(&attr_dataAtoms, 16);
            vec_init(&attr_dataAtom_attrs, 16);
            attr_functors = proc_tbl_make_with_size(16);
            LmnInstrVar i = 0, n;

            READ_VAL(LmnInstrVar, instr, n);
             
            switch (op) {
            case INSTR_ISHLGROUNDINDIRECT:
              {
                LmnInstrVar ai;
                for (; n--; i++) {
                  READ_VAL(LmnInstrVar, instr, ai);
                  if (LMN_ATTR_IS_DATA(at(rc, ai))) {
                    vec_push(&attr_dataAtom_attrs, at(rc, ai));
                    vec_push(&attr_dataAtoms, wt(rc,ai));
                  } else {
                    LmnFunctor f;
                    f = LMN_SATOM_GET_FUNCTOR(wt(rc, ai));
                    proc_tbl_put(attr_functors, f, f);
                  }
                }
                break;
              }
            case INSTR_ISHLGROUND:
              {
                for (; n--; i++) {
                  LmnLinkAttr attr;
                  READ_VAL(LmnLinkAttr, instr, attr);
                  if (LMN_ATTR_IS_DATA(attr)) {
                    LmnAtom at;
                    vec_push(&attr_dataAtom_attrs, attr);
                    READ_DATA_ATOM(at, attr);
                    vec_push(&attr_dataAtoms, at);
                  } else {
                    LmnFunctor f;
                    READ_VAL(LmnFunctor, instr, f);
                    proc_tbl_put(attr_functors, f, f);
                  }
                }
                break;
              }
            }
            /*for (i = 0; i < attr_functors->size ; i++) {
                   if (attr_functors->tbl[i]!=-1) {
                     printf("%d->%d\n", i, attr_functors->tbl[i]);
                   }
            }*/

            b = lmn_mem_is_hlground(srcvec,
                                    avovec,
                                    &natoms,
                                    &attr_functors,
                                    &attr_dataAtoms,
                                    &attr_dataAtom_attrs);
            /*for (i=0; i<vec_num(&attr_dataAtoms);i++) {
                   printf("%d\n", vec_get(&attr_dataAtoms, i));
                   printf("%d\n", vec_get(&attr_dataAtom_attrs, i));
            }*/
            proc_tbl_free(attr_functors);
            vec_destroy(&attr_dataAtoms);
            vec_destroy(&attr_dataAtom_attrs);
            break;
          }
          case INSTR_ISGROUND:
          {
            b = lmn_mem_is_ground(srcvec, avovec, &natoms);
            break;
          }
        }

        free_links(srcvec);
        free_links(avovec);

        if (!b) return FALSE;
        warry_set(rc, funci, natoms, LMN_INT_ATTR, TT_OTHER);
      }

      break;
    }
    case INSTR_UNIQ:
    {
      /*
       * uniq 命令は、
       * "全ての失敗しうるガード命令列の最後尾" かつ
       * "シンボルアトムを生成するガード命令列より前" に
       * 挿入されるように、コンパイラで配置変更を行なっている
       */

      LmnInstrVar llist, n;
      LmnPort port;
      lmn_interned_str id;
      unsigned int i;
      BOOL sh;
      LmnLinkAttr attr;

      port = (LmnPort)lmn_make_output_string_port();
      READ_VAL(LmnInstrVar, instr, llist);

      if (lmn_env.show_hyperlink) {
        sh = TRUE;
        /* MT-UNSAFE!!
         *  --show_hlオプションの有無でlmn_dump_atomから取得できる
         *  バイト列が変わってしまうため、とりあえずの回避策
         *
         *  TODO:
         *    実行時オプション用のフラグデータの書換えは,
         *    フラグをReactCxtオブジェクトに記録させることで,
         *    スレッドセーフにできる */
        lmn_env.show_hyperlink = FALSE;
      }
      else {
        sh = FALSE;
      }

      for (i = 0; i < (int)llist; i++) {
        Vector *srcvec;

        READ_VAL(LmnInstrVar, instr, n);
        srcvec = (Vector *)wt(rc, n);
        attr = (LmnLinkAttr)at(rc, vec_get(srcvec, 0));

        /** 識別子の生成 **/
        /* 引数に直接データアトムが接続されている場合 */
        if (LMN_ATTR_IS_DATA(attr)) {
          switch (attr) {
          case LMN_INT_ATTR:
            {
              char *s = int_to_str(wt(rc, vec_get(srcvec, 0)));
              port_put_raw_s(port, s);
              LMN_FREE(s);
              break;
            }
          case LMN_DBL_ATTR:
            {
              char buf[64];
              sprintf(buf, "%f", *(double*)wt(rc, vec_get(srcvec, 0)));
              port_put_raw_s(port, buf);
              break;
            }
          case LMN_HL_ATTR:
            {
              char buf[16];
              port_put_raw_s(port, EXCLAMATION_NAME);
              sprintf(buf,
                      "%lx",
                      LMN_HL_ID(LMN_HL_ATOM_ROOT_HL(LMN_SATOM(wt(rc, vec_get(srcvec, 0))))));
              port_put_raw_s(port, buf);
              break;
            }
          default: /* int, double, hlink 以外はとりあえず今まで通り */
            lmn_dump_atom(port,
                          (LmnWord)wt(rc, vec_get(srcvec, 0)),
                          (LmnLinkAttr)at(rc, vec_get(srcvec, 0)));
          }
        } else { /* symbol atom */
          lmn_dump_atom(port,
                        (LmnWord)wt(rc, vec_get(srcvec, 0)),
                        (LmnLinkAttr)at(rc, vec_get(srcvec, 0)));
        }
        port_put_raw_s(port, ":");
      }

      id = lmn_intern((char *)lmn_string_c_str(port->data));
      lmn_port_free(port);

      if (sh) lmn_env.show_hyperlink = TRUE;

      /* 履歴表と照合 */
      if (st_is_member(lmn_rule_get_history_tbl(rule), (st_data_t)id)) return FALSE;

      /* 履歴に挿入 */
      st_insert(lmn_rule_get_history_tbl(rule), (st_data_t)id, 0);
      lmn_rule_set_pre_id(rule, id);

      break;
    }
    case INSTR_NEWHLINKWITHATTR:
    case INSTR_NEWHLINKWITHATTRINDIRECT:
    case INSTR_NEWHLINK:
    {
      /* 全ての失敗しうるガード制約よりも後で実行されるように、
       * コンパイラで配置変更を行なっている
       */

      LmnInstrVar atomi;
      READ_VAL(LmnInstrVar, instr, atomi);
      
      switch (op) {
        case INSTR_NEWHLINKWITHATTR:
          {
            LmnAtom ap;
            LmnLinkAttr attr;
            READ_VAL(LmnLinkAttr, instr, attr);
            if (LMN_ATTR_IS_DATA(attr)) {
              READ_DATA_ATOM(ap, attr);
            } else {
              LmnFunctor f;
              READ_VAL(LmnFunctor, instr, f);
              ap = LMN_ATOM(lmn_new_atom(f));
              attr = 0;//シンボルアトムということを表す。値に意味はない。
              if (LMN_SATOM_GET_ARITY(LMN_SATOM(ap))>1) {
                lmn_fatal("hyperlink's attribute takes only an unary atom");
              }
            }
            warry_set(rc, atomi, lmn_hyperlink_new_with_attr(ap, attr), LMN_HL_ATTR, TT_ATOM);
            break;
          }
        case INSTR_NEWHLINKWITHATTRINDIRECT:
          {
            LmnAtom ap;
            LmnLinkAttr attr;
            LmnInstrVar atomi2;  //変数名どうにかしたい。
            READ_VAL(LmnInstrVar, instr, atomi2);
            ap =lmn_copy_atom(wt(rc, atomi2), at(rc, atomi2));
            attr = at(rc, atomi2);
            if (!LMN_ATTR_IS_DATA(at(rc, atomi2)) &&
                                  LMN_SATOM_GET_ARITY(LMN_SATOM(ap))>1) {
                  lmn_fatal("hyperlink's attribute takes only an unary atom");
                }
            warry_set(rc, atomi, lmn_hyperlink_new_with_attr(ap, attr), LMN_HL_ATTR, TT_ATOM);
            break;
          }
        case INSTR_NEWHLINK:
          warry_set(rc, atomi, lmn_hyperlink_new(), LMN_HL_ATTR, TT_ATOM);      
          break;
      }
      break;
    }
    case INSTR_MAKEHLINK:
    {
      /* // 未実装
       *
       * i(N) :- make(N, $x), N1 = N-1 | i(N1), hoge($x).
       * のようにして、int(N)の値をIDとするhyperlinkを生成できるような機能があると
       * 性能測定にとても便利かも
       * (構文(記法？)はこれじゃないとしても、hyperlinkへの値の束縛に若干関係しそうなにほひ)
       */
      break;
    }
    case INSTR_ISHLINK:
    {
      LmnInstrVar atomi;
      READ_VAL(LmnInstrVar, instr, atomi);

      if (!LMN_ATTR_IS_HL(at(rc, atomi))) return FALSE;

      break;
    }
    case INSTR_GETATTRATOM:
    {
      LmnInstrVar dstatomi, atomi;
      READ_VAL(LmnInstrVar, instr, dstatomi);
      READ_VAL(LmnInstrVar, instr, atomi);

      warry_set(rc, dstatomi,
                LMN_HL_ATTRATOM(lmn_hyperlink_at_to_hl(LMN_SATOM(wt(rc, atomi)))),
                LMN_HL_ATTRATOM_ATTR(lmn_hyperlink_at_to_hl(LMN_SATOM(wt(rc, atomi)))),
                TT_OTHER);
      break;
    }
    case INSTR_GETNUM:
    {
      LmnInstrVar dstatomi, atomi;

      /* ISHLINKチェック済み */
      READ_VAL(LmnInstrVar, instr, dstatomi);
      READ_VAL(LmnInstrVar, instr, atomi);

      warry_set(rc, dstatomi,
                lmn_hyperlink_element_num(lmn_hyperlink_at_to_hl(LMN_SATOM(wt(rc, atomi)))),
                LMN_INT_ATTR,
                TT_OTHER);
      break;
    }
    case INSTR_UNIFYHLINKS:
    {
      LmnSAtom atom;
      LmnInstrVar memi, atomi;
      LmnLinkAttr attr1, attr2;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, atomi);

      atom = LMN_SATOM(wt(rc, atomi));

      attr1 = LMN_SATOM_GET_ATTR(atom, 0);
      attr2 = LMN_SATOM_GET_ATTR(atom, 1);

      /* >< の両辺のアトムがハイパーリンクであれば併合 */
      if (LMN_ATTR_IS_HL(attr1) && LMN_ATTR_IS_HL(attr2)) {
        LmnMembrane *m;
        LmnSAtom atom1, atom2;
        HyperLink *hl1, *hl2;

        m = (LmnMembrane *)wt(rc, memi);
        atom1 = LMN_SATOM(LMN_SATOM_GET_LINK(atom, 0));
        atom2 = LMN_SATOM(LMN_SATOM_GET_LINK(atom, 1));

        hl1 = lmn_hyperlink_at_to_hl(atom1);
        hl2 = lmn_hyperlink_at_to_hl(atom2);

        if (LMN_SATOM_GET_ARITY(atom)==2) {//二引数の場合は一つ目のハイパーリンクの属性を継承する
          lmn_hyperlink_unify(hl1, hl2, LMN_HL_ATTRATOM(hl1), LMN_HL_ATTRATOM_ATTR(hl1));
        } else if (LMN_SATOM_GET_ARITY(atom)==3) {//三引数の場合は三引数目を併合後の属性とする
          LmnAtom attrAtom;
          attrAtom  = LMN_ATOM(LMN_SATOM_GET_LINK(atom, 2));
          lmn_hyperlink_unify(hl1, hl2, attrAtom, LMN_SATOM_GET_ATTR(atom, 2)); 
        } else {
          lmn_fatal("too many arguments to >< atom");
        }

        lmn_mem_delete_atom(m, wt(rc, atomi), at(rc, atomi));
        lmn_mem_delete_atom(m, (LmnWord)atom1, (LmnWord)attr1);
        lmn_mem_delete_atom(m, (LmnWord)atom2, (LmnWord)attr2);
      }
      break;
    }
    case INSTR_FINDPROCCXT:
    {
      /** 同名の型付きプロセス文脈名を持つルールを最適化モードで実行するための命令
       * hyperlink専用(2010/10/10時点)
       *
       * Java版コンパイラ側で--hl-optを付けてコンパイルすることで、findatomの前に挿入される
       * SLIM側で--hlオプション指定で実行可能（オプション無しで実行されるとwarning）
       *
       * cf. 同名の型付きプロセス文脈名の分離
       *     a($x), b($x) :- ...
       *   → a($x), a($x0) :- hlink($x), $x = $x0 | ...
       *   同じ名前の型付きプロセス文脈名を記述すると、片方の名前をユニークなものに変更し、
       *   ガードで型チェック、構造比較を行うルールに自動的に変換してくれる
       *   便宜的に、元の名前（ここでの$x）をオリジナル、新たに生成された名前（ここでの$x0）をクローンと呼んでいる
       */
      LmnInstrVar atom1, length1, arg1, atom2, length2, arg2;
      SameProcCxt *spc1, *spc2;

      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, length1);
      READ_VAL(LmnInstrVar, instr, arg1);
      READ_VAL(LmnInstrVar, instr, atom2);
      READ_VAL(LmnInstrVar, instr, length2);
      READ_VAL(LmnInstrVar, instr, arg2);

      if (!RC_HLINK_SPC(rc)) {
        lmn_sameproccxt_init(rc);
      }

      if (!hashtbl_contains(RC_HLINK_SPC(rc), (HashKeyType)atom1)) {
        spc1 = lmn_sameproccxt_spc_make(atom1, length1);
        hashtbl_put(RC_HLINK_SPC(rc), (HashKeyType)atom1, (HashValueType)spc1);
      }
      else {
        spc1 = (SameProcCxt *)hashtbl_get(RC_HLINK_SPC(rc), (HashKeyType)atom1);
      }

      if (!LMN_SPC_PC(spc1, arg1)) {
        LMN_SPC_PC(spc1, arg1) = lmn_sameproccxt_pc_make(atom1, arg1, NULL);
      }

      if (!hashtbl_contains(RC_HLINK_SPC(rc), (HashKeyType)atom2)) {
        spc2 = lmn_sameproccxt_spc_make(atom2, length2);
        hashtbl_put(RC_HLINK_SPC(rc), (HashKeyType)atom2, (HashValueType)spc2);
      }
      else {
        spc2 = (SameProcCxt *)hashtbl_get(RC_HLINK_SPC(rc), (HashKeyType)atom2);
      }

      if (!LMN_SPC_PC(spc2, arg2)) {
        LMN_SPC_PC(spc2, arg2) = lmn_sameproccxt_pc_make(atom2, arg2, LMN_SPC_PC(spc1, arg1));
      }

      break;
    }
    case INSTR_EQGROUND:
    case INSTR_NEQGROUND:
    {
      LmnInstrVar srci, dsti;
      Vector *srcvec, *dstvec;
      BOOL ret_flag;

      READ_VAL(LmnInstrVar, instr, srci);
      READ_VAL(LmnInstrVar, instr, dsti);

      srcvec = links_from_idxs((Vector *)wt(rc, srci), rc_warry(rc));
      dstvec = links_from_idxs((Vector *)wt(rc, dsti), rc_warry(rc));

      ret_flag = lmn_mem_cmp_ground(srcvec, dstvec);

      free_links(srcvec);
      free_links(dstvec);

      if ((!ret_flag && INSTR_EQGROUND  == op) ||
          (ret_flag  && INSTR_NEQGROUND == op)) {
        return FALSE;
      }
      break;
    }
    case INSTR_COPYHLGROUND:
    case INSTR_COPYHLGROUNDINDIRECT:
    case INSTR_COPYGROUND:
    {
      LmnInstrVar dstlist, srclist, memi;
      Vector *srcvec, *dstlovec, *retvec; /* 変数番号のリスト */
      ProcessTbl atommap;
      ProcessTbl hlinkmap;

      READ_VAL(LmnInstrVar, instr, dstlist);
      READ_VAL(LmnInstrVar, instr, srclist);
      READ_VAL(LmnInstrVar, instr, memi);

      /* リンクオブジェクトのベクタを構築 */
      srcvec = links_from_idxs((Vector *)wt(rc, srclist), rc_warry(rc));
      
      switch (op) {
        case INSTR_COPYHLGROUND:
        case INSTR_COPYHLGROUNDINDIRECT:
        {
          ProcessTbl attr_functors;
          Vector attr_dataAtoms;
          Vector attr_dataAtom_attrs;
          vec_init(&attr_dataAtoms, 16);
          vec_init(&attr_dataAtom_attrs, 16);
          attr_functors = proc_tbl_make_with_size(16);
          LmnInstrVar i = 0, n;

          READ_VAL(LmnInstrVar, instr, n);
             
          switch (op) {
          case INSTR_COPYHLGROUNDINDIRECT:
            {
              LmnInstrVar ai;
              for (; n--; i++) {
                READ_VAL(LmnInstrVar, instr, ai);
                if (LMN_ATTR_IS_DATA(at(rc, ai))) {
                  vec_push(&attr_dataAtom_attrs, at(rc, ai));
                  vec_push(&attr_dataAtoms, wt(rc, ai));
                } else {
                  LmnFunctor f;
                  f = LMN_SATOM_GET_FUNCTOR(wt(rc, ai));
                  proc_tbl_put(attr_functors, f, f);
                }
              }
              break;
            }
          case INSTR_COPYHLGROUND:
            {
              for (; n--; i++) {
                LmnLinkAttr attr;
                READ_VAL(LmnLinkAttr, instr, attr);
                if (LMN_ATTR_IS_DATA(attr)) {
                  LmnAtom at;
                  vec_push(&attr_dataAtom_attrs, attr);
                  READ_DATA_ATOM(at, attr);
                  vec_push(&attr_dataAtoms, at);
                } else {
                  LmnFunctor f;
                  READ_VAL(LmnFunctor, instr, f);
                  proc_tbl_put(attr_functors, f, f);
                }
              }
              break;
            }
          }
          lmn_mem_copy_hlground((LmnMembrane *)wt(rc, memi),
                              srcvec,
                             &dstlovec,
                             &atommap,
                             &hlinkmap,
                             &attr_functors,
                             &attr_dataAtoms,
                             &attr_dataAtom_attrs);

          break;
        }
        case INSTR_COPYGROUND:
          lmn_mem_copy_ground((LmnMembrane *)wt(rc, memi),
                              srcvec,
                             &dstlovec,
                             &atommap);
          break;
      }
      free_links(srcvec);

      /* 返り値の作成 */
      retvec = vec_make(2);
      vec_push(retvec, (LmnWord)dstlovec);
      vec_push(retvec, (LmnWord)atommap);
      warry_set(rc, dstlist, retvec, LIST_AND_MAP, TT_OTHER);

      /* 解放のための再帰。ベクタを解放するための中間語命令がない */
      interpret(rc, rule, instr);

      free_links(dstlovec);
      vec_free(retvec);

      return TRUE; /* COPYGROUNDはボディに出現する */
    }
    case INSTR_REMOVEHLGROUND:
    case INSTR_REMOVEHLGROUNDINDIRECT:
    case INSTR_FREEHLGROUND:
    case INSTR_FREEHLGROUNDINDIRECT:
    case INSTR_REMOVEGROUND:
    case INSTR_FREEGROUND:
    {
      LmnInstrVar listi, memi;
      Vector *srcvec; /* 変数番号のリスト */

      READ_VAL(LmnInstrVar, instr, listi);
      if (INSTR_REMOVEGROUND == op || INSTR_REMOVEHLGROUND == op
          || INSTR_REMOVEHLGROUNDINDIRECT == op) {
        READ_VAL(LmnInstrVar, instr, memi);
      } else {
        memi = 0;
      }
      srcvec = links_from_idxs((Vector *)wt(rc, listi), rc_warry(rc));

      switch (op) {
        case INSTR_REMOVEHLGROUND:
        case INSTR_REMOVEHLGROUNDINDIRECT: 
        case INSTR_FREEHLGROUND:
        case INSTR_FREEHLGROUNDINDIRECT:
        { 
          ProcessTbl attr_functors;
          Vector attr_dataAtoms;
          Vector attr_dataAtom_attrs;
          vec_init(&attr_dataAtoms, 16);
          vec_init(&attr_dataAtom_attrs, 16);
          attr_functors = proc_tbl_make_with_size(16);
          LmnInstrVar i = 0, n;

          READ_VAL(LmnInstrVar, instr, n);
             
          switch (op) {
          case INSTR_REMOVEHLGROUNDINDIRECT:
          case INSTR_FREEHLGROUNDINDIRECT:
            {
              LmnInstrVar ai;
              for (; n--; i++) {
                READ_VAL(LmnInstrVar, instr, ai);
                if (LMN_ATTR_IS_DATA(at(rc, ai))) {
                  vec_push(&attr_dataAtom_attrs, at(rc, ai));
                  vec_push(&attr_dataAtoms, wt(rc, ai));
                } else {
                  LmnFunctor f;
                  f = LMN_SATOM_GET_FUNCTOR(wt(rc, ai));
                  proc_tbl_put(attr_functors, f, f);
                }
              }
              break;
            }
          case INSTR_REMOVEHLGROUND:
          case INSTR_FREEHLGROUND:
            {
              for (; n--; i++) {
                LmnLinkAttr attr;
                READ_VAL(LmnLinkAttr, instr, attr);
                if (LMN_ATTR_IS_DATA(attr)) {
                  LmnAtom at;
                  vec_push(&attr_dataAtom_attrs, attr);
                  READ_DATA_ATOM(at, attr);
                  vec_push(&attr_dataAtoms, at);
                } else {
                  LmnFunctor f;
                  READ_VAL(LmnFunctor, instr, f);
                  proc_tbl_put(attr_functors, f, f);
                }
              }
              break;
            }
          }
            switch (op) {
              case INSTR_REMOVEHLGROUND:
              case INSTR_REMOVEHLGROUNDINDIRECT:
                lmn_mem_remove_hlground((LmnMembrane *)wt(rc, memi),
                    srcvec,
                    &attr_functors,
                    &attr_dataAtoms,
                    &attr_dataAtom_attrs);
                break;
              case INSTR_FREEHLGROUND:
              case INSTR_FREEHLGROUNDINDIRECT:
                lmn_mem_free_hlground(srcvec,  // this may also cause a bug, see 15 lines below
                    &attr_functors,
                    &attr_dataAtoms,
                    &attr_dataAtom_attrs);
                break;
            }
            proc_tbl_free(attr_functors);
            vec_destroy(&attr_dataAtoms);
            vec_destroy(&attr_dataAtom_attrs);
            break;
          }
      case INSTR_REMOVEGROUND:
        lmn_mem_remove_ground((LmnMembrane *)wt(rc, memi), srcvec);
        break;
      case INSTR_FREEGROUND:
        lmn_mem_free_ground(srcvec);
        break;
      }

      free_links(srcvec);

      break;
    }
    case INSTR_ISUNARY:
    {
      LmnInstrVar atomi;
      READ_VAL(LmnInstrVar, instr, atomi);

      if (LMN_ATTR_IS_DATA(at(rc, atomi))) {
        switch (at(rc, atomi)) {
        case LMN_SP_ATOM_ATTR:
          /* スペシャルアトムはgroundの結果をunaryの結果とする */
          if (!SP_ATOM_IS_GROUND(wt(rc, atomi))) {
            return FALSE;
          }
          break;
        default:
          break;
        }
      }
      else if (LMN_SATOM_GET_ARITY(wt(rc, atomi)) != 1)
        return FALSE;
      break;
    }
    case INSTR_ISINT:
    {
      LmnInstrVar atomi;
      READ_VAL(LmnInstrVar, instr, atomi);

      if (at(rc, atomi) != LMN_INT_ATTR)
        return FALSE;
      break;
    }
    case INSTR_ISFLOAT:
    {
      LmnInstrVar atomi;
      READ_VAL(LmnInstrVar, instr, atomi);

      if(at(rc, atomi) != LMN_DBL_ATTR)
        return FALSE;
      break;
    }
    case INSTR_ISSTRING:
    {
      LmnInstrVar atomi;

      READ_VAL(LmnInstrVar, instr, atomi);

      if(!lmn_is_string(wt(rc, atomi), at(rc, atomi)))
        return FALSE;
      break;
    }
    case INSTR_ISINTFUNC:
    {
      LmnInstrVar funci;
      READ_VAL(LmnInstrVar, instr, funci);

      if(at(rc, funci) != LMN_INT_ATTR)
        return FALSE;
      break;
    }
    case INSTR_ISFLOATFUNC:
    {
      LmnInstrVar funci;
      READ_VAL(LmnInstrVar, instr, funci);

      if(at(rc, funci) != LMN_DBL_ATTR)
        return FALSE;
      break;
    }
    case INSTR_COPYATOM:
    {
      LmnInstrVar atom1, memi, atom2;

      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, atom2);

      warry_set(rc, atom1,
                lmn_copy_atom(wt(rc, atom2), at(rc, atom2)),
                at(rc, atom2),
                TT_OTHER);
      lmn_mem_push_atom((LmnMembrane *)wt(rc, memi), wt(rc, atom1), at(rc, atom1));
      break;
    }
    case INSTR_EQATOM:
    {
      LmnInstrVar atom1, atom2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      /* データアトムは１引数なので,この命令が出る状況では
         では常にFALSEのはず */
      if (LMN_ATTR_IS_DATA(at(rc, atom1)) || LMN_ATTR_IS_DATA(at(rc, atom2)) ||
          LMN_SATOM(wt(rc, atom1)) != LMN_SATOM(wt(rc, atom2)))
        return FALSE;
      break;
    }
    case INSTR_NEQATOM:
    {
      LmnInstrVar atom1, atom2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      if (!(LMN_ATTR_IS_DATA(at(rc, atom1)) || LMN_ATTR_IS_DATA(at(rc, atom2)) ||
            LMN_SATOM(wt(rc, atom1)) != LMN_SATOM(wt(rc, atom2))))
        return FALSE;
      break;
    }
    case INSTR_EQMEM:
    {
      LmnInstrVar mem1, mem2;

      READ_VAL(LmnInstrVar, instr, mem1);
      READ_VAL(LmnInstrVar, instr, mem2);
      if (wt(rc, mem1) != wt(rc, mem2)) return FALSE;
      break;
    }
    case INSTR_NEQMEM:
    {
      LmnInstrVar mem1, mem2;
      READ_VAL(LmnInstrVar, instr, mem1);
      READ_VAL(LmnInstrVar, instr, mem2);

      if(wt(rc, mem1) == wt(rc, mem2)) return FALSE;
      break;
    }
    case INSTR_STABLE:
    {
      LmnInstrVar memi;
      READ_VAL(LmnInstrVar, instr, memi);

      if (lmn_mem_is_active((LmnMembrane *)wt(rc, memi))) {
        return FALSE;
      }

      if (RC_GET_MODE(rc, REACT_ND) && RC_MC_USE_DPOR(rc)) {
        LmnMembrane *m = (LmnMembrane *)wt(rc, memi);
        dpor_LHS_flag_add(RC_POR_DATA(rc), lmn_mem_id(m), LHS_MEM_STABLE);
        interpret(rc, rule, instr);
        dpor_LHS_flag_remove(RC_POR_DATA(rc), lmn_mem_id(m), LHS_MEM_STABLE);
        return FALSE; /* 全ての候補取得のためにNDは常にFALSEを返す仕様 */
      }

      break;
    }
    case INSTR_NEWLIST:
    {
      LmnInstrVar listi;
      Vector *listvec = vec_make(16);
      READ_VAL(LmnInstrVar, instr, listi);
      warry_set(rc, listi, listvec, 0, TT_OTHER);

      /* 解放のための再帰 */
      if (interpret(rc, rule, instr)) {
        vec_free(listvec);
        return TRUE;
      }
      else {
        vec_free(listvec);
        return FALSE;
      }
      break;
    }
    case INSTR_ADDTOLIST:
    {
      LmnInstrVar listi, linki;
      READ_VAL(LmnInstrVar, instr, listi);
      READ_VAL(LmnInstrVar, instr, linki);
      vec_push((Vector *)wt(rc, listi), linki);

      break;
    }
    case INSTR_GETFROMLIST:
    {
      LmnInstrVar dsti, listi, posi;
      READ_VAL(LmnInstrVar, instr, dsti);
      READ_VAL(LmnInstrVar, instr, listi);
      READ_VAL(LmnInstrVar, instr, posi);

      switch (at(rc, listi)) {
        case LIST_AND_MAP:
          if (posi == 0) {
            warry_set(rc, dsti,
                      vec_get((Vector *)wt(rc, listi), (unsigned int)posi),
                      LINK_LIST,
                      TT_OTHER);
          } else if (posi == 1) {
            warry_set(rc, dsti,
                      vec_get((Vector *)wt(rc, listi), (unsigned int)posi),
                      MAP,
                      TT_OTHER);
          } else {
            lmn_fatal("unexpected attribute @instr_getfromlist");
          }
          break;
        case LINK_LIST: /* LinkObjをfreeするのはここ？ */
        {
          LinkObj lo = (LinkObj)vec_get((Vector *)wt(rc, listi), (unsigned int)posi);
          warry_set(rc, dsti, lo->ap, lo->pos, TT_ATOM);
          break;
        }
      }
      break;
    }
    case INSTR_IADD:
    {
      LmnInstrVar dstatom, atom1, atom2;
      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);
      warry_set(rc, dstatom,
                ((long)wt(rc, atom1) + (long)wt(rc, atom2)),
                LMN_INT_ATTR,
                TT_ATOM);
      break;
    }
    case INSTR_ISUB:
    {
      LmnInstrVar dstatom, atom1, atom2;
      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      warry_set(rc, dstatom,
                ((long)wt(rc, atom1) - (long)wt(rc, atom2)),
                LMN_INT_ATTR,
                TT_ATOM);
      break;
    }
    case INSTR_IMUL:
    {
      LmnInstrVar dstatom, atom1, atom2;
      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      warry_set(rc, dstatom,
                ((long)wt(rc, atom1) * (long)wt(rc, atom2)),
                LMN_INT_ATTR,
                TT_ATOM);
      break;
    }
    case INSTR_IDIV:
    {
      LmnInstrVar dstatom, atom1, atom2;
      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      warry_set(rc, dstatom,
                ((long)wt(rc, atom1) / (long)wt(rc, atom2)),
                LMN_INT_ATTR,
                TT_ATOM);

      break;
    }
    case INSTR_INEG:
    {
      LmnInstrVar dstatom, atomi;
      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atomi);
      warry_set(rc, dstatom,
                (-(long)wt(rc, atomi)),
                LMN_INT_ATTR,
                TT_ATOM);
      break;
    }
    case INSTR_IMOD:
    {
      LmnInstrVar dstatom, atom1, atom2;
      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      warry_set(rc, dstatom,
                ((long)wt(rc, atom1) % (long)wt(rc, atom2)),
                LMN_INT_ATTR,
                TT_ATOM);
      break;
    }
    case INSTR_INOT:
    {
      LmnInstrVar dstatom, atomi;
      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atomi);
      warry_set(rc, dstatom,
                (~(int)wt(rc, atomi)),
                LMN_INT_ATTR,
                TT_ATOM);
      break;
    }
    case INSTR_IAND:
    {
      LmnInstrVar dstatom, atom1, atom2;
      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      warry_set(rc, dstatom,
                ((long)wt(rc, atom1) & (long)wt(rc, atom2)),
                LMN_INT_ATTR,
                TT_ATOM);
      break;
    }
    case INSTR_IOR:
    {
      LmnInstrVar dstatom, atom1, atom2;
      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      warry_set(rc, dstatom,
                ((long)wt(rc, atom1) | (long)wt(rc, atom2)),
                LMN_INT_ATTR,
                TT_ATOM);

      break;
    }
    case INSTR_IXOR:
    {
      LmnInstrVar dstatom, atom1, atom2;
      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      warry_set(rc, dstatom,
               ((long)wt(rc, atom1) ^ (long)wt(rc, atom2)),
               LMN_INT_ATTR,
               TT_ATOM);
      break;
    }
    case INSTR_ILT:
    {
      LmnInstrVar atom1, atom2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      if (!((long)wt(rc, atom1) < (long)wt(rc, atom2))) return FALSE;
      break;
    }
    case INSTR_ILE:
    {
      LmnInstrVar atom1, atom2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      if (!((long)wt(rc, atom1) <= (long)wt(rc, atom2))) return FALSE;
      break;
    }
    case INSTR_IGT:
    {
      LmnInstrVar atom1, atom2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      if (!((long)wt(rc, atom1) > (long)wt(rc, atom2))) return FALSE;
      break;
    }
    case INSTR_IGE:
    {
      LmnInstrVar atom1, atom2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      if (!((long)wt(rc, atom1) >= (long)wt(rc, atom2))) return FALSE;
      break;
    }
    case INSTR_IEQ:
    {
      LmnInstrVar atom1, atom2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      if (!((long)wt(rc, atom1) == (long)wt(rc, atom2))) return FALSE;
      break;
    }
    case INSTR_INE:
    {
      LmnInstrVar atom1, atom2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      if (!((long)wt(rc, atom1) != (long)wt(rc, atom2))) return FALSE;
      break;
    }
    case INSTR_ILTFUNC:
    {
      LmnInstrVar func1, func2;
      READ_VAL(LmnInstrVar, instr, func1);
      READ_VAL(LmnInstrVar, instr, func2);

      if (!((long)wt(rc, func1) < (long)wt(rc, func2))) return FALSE;
      break;
    }
    case INSTR_ILEFUNC:
    {
      LmnInstrVar func1, func2;
      READ_VAL(LmnInstrVar, instr, func1);
      READ_VAL(LmnInstrVar, instr, func2);

      if (!((long)wt(rc, func1) <= (long)wt(rc, func2))) return FALSE;
      break;
    }
    case INSTR_IGTFUNC:
    {
      LmnInstrVar func1, func2;
      READ_VAL(LmnInstrVar, instr, func1);
      READ_VAL(LmnInstrVar, instr, func2);

      if (!((long)wt(rc, func1) > (long)wt(rc, func2))) return FALSE;
      break;
    }
    case INSTR_IGEFUNC:
    {
      LmnInstrVar func1, func2;
      READ_VAL(LmnInstrVar, instr, func1);
      READ_VAL(LmnInstrVar, instr, func2);

      if (!((long)wt(rc, func1) >= (long)wt(rc, func2))) return FALSE;
      break;
    }
    case  INSTR_FADD:
    {
      LmnInstrVar dstatom, atom1, atom2;
      double *d;
      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      d = LMN_MALLOC(double);
      *d = *(double *)wt(rc, atom1) + *(double *)wt(rc, atom2);
      warry_set(rc, dstatom, d, LMN_DBL_ATTR, TT_ATOM);
      break;
    }
    case  INSTR_FSUB:
    {
      LmnInstrVar dstatom, atom1, atom2;
      double *d;
      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      d = LMN_MALLOC(double);
      *d = *(double *)wt(rc, atom1) - *(double *)wt(rc, atom2);
      warry_set(rc, dstatom, d, LMN_DBL_ATTR, TT_ATOM);
      break;
    }
    case  INSTR_FMUL:
    {
      LmnInstrVar dstatom, atom1, atom2;
      double *d;

      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      d = LMN_MALLOC(double);
      *d = *(double *)wt(rc, atom1) * *(double *)wt(rc, atom2);
      warry_set(rc, dstatom, d, LMN_DBL_ATTR, TT_ATOM);
      break;
    }
    case  INSTR_FDIV:
    {
      LmnInstrVar dstatom, atom1, atom2;
      double *d;

      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      d = LMN_MALLOC(double);
      *d = *(double *)wt(rc, atom1) / *(double *)wt(rc, atom2);
      warry_set(rc, dstatom, d, LMN_DBL_ATTR, TT_ATOM);
      break;
    }
    case  INSTR_FNEG:
    {
      LmnInstrVar dstatom, atomi;
      double *d;
      READ_VAL(LmnInstrVar, instr, dstatom);
      READ_VAL(LmnInstrVar, instr, atomi);

      d = LMN_MALLOC(double);
      *d = -*(double *)wt(rc, atomi);
      warry_set(rc, dstatom, d, LMN_DBL_ATTR, TT_ATOM);
      break;
    }
    case INSTR_FLT:
    {
      LmnInstrVar atom1, atom2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      if (!(*(double*)wt(rc, atom1) < *(double*)wt(rc, atom2))) return FALSE;
      break;
    }
    case INSTR_FLE:
    {
      LmnInstrVar atom1, atom2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      if (!(*(double*)wt(rc, atom1) <= *(double*)wt(rc, atom2))) return FALSE;
      break;
    }
    case INSTR_FGT:
    {
      LmnInstrVar atom1, atom2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      if(!(*(double*)wt(rc, atom1) > *(double*)wt(rc, atom2))) return FALSE;
      break;
    }
    case INSTR_FGE:
    {
      LmnInstrVar atom1, atom2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      if(!(*(double*)wt(rc, atom1) >= *(double*)wt(rc, atom2))) return FALSE;
      break;
    }
    case INSTR_FEQ:
    {
      LmnInstrVar atom1, atom2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      if(!(*(double*)wt(rc, atom1) == *(double*)wt(rc, atom2))) return FALSE;
      break;
    }
    case INSTR_FNE:
    {
      LmnInstrVar atom1, atom2;
      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      if(!(*(double*)wt(rc, atom1) != *(double*)wt(rc, atom2))) return FALSE;
      break;
    }
    case INSTR_ALLOCATOM:
    {
      LmnInstrVar atomi;
      LmnLinkAttr attr;

      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnLinkAttr, instr, attr);
      at_set(rc, atomi, attr);
      if (LMN_ATTR_IS_DATA(attr)) {
        READ_CONST_DATA_ATOM(wt(rc, atomi), at(rc, atomi), tt(rc, atomi));
      } else { /* symbol atom */
        LmnFunctor f;
/*         fprintf(stderr, "symbol atom can't be created in GUARD\n"); */
/*         exit(EXIT_FAILURE); */
        READ_VAL(LmnFunctor, instr, f);

        /* 本来のallocatomは格納するのは定数アトムだが、簡単のためにファンクタを格納する */
        wt_set(rc, atomi, f);
      }
      tt_set(rc, atomi, TT_OTHER); /* ヘッドに存在しないのでコピー対象外 */
      break;
    }
    case INSTR_ALLOCATOMINDIRECT:
    {
      LmnInstrVar atomi;
      LmnInstrVar srcatomi;

      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnInstrVar, instr, srcatomi);

      if (LMN_ATTR_IS_DATA(at(rc, srcatomi))) {
        if (LMN_ATTR_IS_EX(at(rc, srcatomi))) {
          wt_set(rc, atomi, wt(rc, srcatomi));
        } else {
          wt_set(rc, atomi, lmn_copy_data_atom(wt(rc, srcatomi), at(rc, srcatomi)));
        }
        at_set(rc, atomi, at(rc, srcatomi));
        tt_set(rc, atomi, TT_OTHER);
      } else { /* symbol atom */
        fprintf(stderr, "symbol atom can't be created in GUARD\n");
        exit(EXIT_FAILURE);
      }
      break;
    }
    case INSTR_SAMEFUNC:
    {
      LmnInstrVar atom1, atom2;

      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, atom2);

      if (!lmn_eq_func(wt(rc, atom1), at(rc, atom1),
                       wt(rc, atom2), at(rc, atom2)))
        return FALSE;
      break;
    }
    case INSTR_GETFUNC:
    {
      LmnInstrVar funci, atomi;

      READ_VAL(LmnInstrVar, instr, funci);
      READ_VAL(LmnInstrVar, instr, atomi);

      if(LMN_ATTR_IS_DATA(at(rc, atomi))) {
        /* ここで得るファンクタはガード命令中で一時的に使われるだけなので
           double はポインタのコピーで十分なはず */
        warry_set(rc, funci, wt(rc, atomi), at(rc, atomi), TT_OTHER);
      }
      else {
        warry_set(rc, funci, LMN_SATOM_GET_FUNCTOR(wt(rc, atomi)), at(rc, atomi), TT_OTHER);
      }
      break;
    }
    case INSTR_PRINTINSTR:
    {
      char c;

      while (TRUE) {
        READ_VAL(char, instr, c);
        if (!c) break;
        fprintf(stderr, "%c", c);
      }
      goto LOOP;
    }
    case INSTR_SETMEMNAME:
    {
      LmnInstrVar memi;
      lmn_interned_str name;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(lmn_interned_str, instr, name);
      lmn_mem_set_name((LmnMembrane *)wt(rc, memi), name);
      break;
    }
    case INSTR_COPYRULES:
    {
      LmnInstrVar destmemi, srcmemi;
      unsigned int i;
      struct Vector *v;

      READ_VAL(LmnInstrVar, instr, destmemi);
      READ_VAL(LmnInstrVar, instr, srcmemi);
      v = &((LmnMembrane *)wt(rc, srcmemi))->rulesets;
      for (i = 0; i< v->num; i++) {
        LmnRuleSet cp = lmn_ruleset_copy((LmnRuleSet)vec_get(v, i));
        lmn_mem_add_ruleset((LmnMembrane *)wt(rc, destmemi), cp);
        if (RC_GET_MODE(rc, REACT_ATOMIC)) {
          /* atomic step中にatomic setをコピーした場合のため */
          lmn_ruleset_invalidate_atomic(cp);
        }
      }
      break;
    }
    case INSTR_REMOVEPROXIES:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      lmn_mem_remove_proxies((LmnMembrane *)wt(rc, memi));
      break;
    }
    case INSTR_INSERTPROXIES:
    {
      LmnInstrVar parentmemi, childmemi;

      READ_VAL(LmnInstrVar, instr, parentmemi);
      READ_VAL(LmnInstrVar, instr, childmemi);
      lmn_mem_insert_proxies((LmnMembrane *)wt(rc, parentmemi),
                             (LmnMembrane *)wt(rc, childmemi));
      break;
    }
    case INSTR_DELETECONNECTORS:
    {
      LmnInstrVar srcset, srcmap;
      HashSet *delset;
      ProcessTbl delmap;
      HashSetIterator it;
      READ_VAL(LmnInstrVar, instr, srcset);
      READ_VAL(LmnInstrVar, instr, srcmap);

      delset = (HashSet *)wt(rc, srcset);
      delmap = (ProcessTbl)wt(rc, srcmap);

      for(it = hashset_iterator(delset); !hashsetiter_isend(&it); hashsetiter_next(&it)) {
        LmnSAtom orig, copy;
        LmnWord t;

        orig = LMN_SATOM(hashsetiter_entry(&it));
        t = 0;
        proc_tbl_get_by_atom(delmap, orig, &t);
        copy = LMN_SATOM(t);

        lmn_mem_unify_symbol_atom_args(copy, 0, copy, 1);
        /* mem がないので仕方なく直接アトムリストをつなぎ変える.
         * UNIFYアトムはnatomに含まれないので大丈夫 */
        remove_from_atomlist(copy, NULL);

        lmn_delete_atom(copy);
      }

      proc_tbl_free(delmap);
      break;
    }
    case INSTR_REMOVETOPLEVELPROXIES:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      lmn_mem_remove_toplevel_proxies((LmnMembrane *)wt(rc, memi));
      break;
    }
    case INSTR_DEREFFUNC:
    {
      LmnInstrVar funci, atomi, pos;
      LmnLinkAttr attr;

      READ_VAL(LmnInstrVar, instr, funci);
      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnLinkAttr, instr, pos);

      attr = LMN_SATOM_GET_ATTR(LMN_SATOM(wt(rc, atomi)), pos);
      if (LMN_ATTR_IS_DATA(attr)) {
        warry_set(rc, funci,
                  LMN_SATOM_GET_LINK(LMN_SATOM(wt(rc, atomi)), pos),
                  attr,
                  TT_OTHER);
      }
      else { /* symbol atom */
        warry_set(rc, funci,
                  LMN_SATOM_GET_FUNCTOR(LMN_SATOM_GET_LINK(LMN_SATOM(wt(rc, atomi)), pos)),
                  attr,
                  TT_OTHER);
      }
      break;
    }
    case INSTR_LOADFUNC:
    {
      LmnInstrVar funci;
      LmnLinkAttr attr;

      READ_VAL(LmnInstrVar, instr, funci);
      READ_VAL(LmnLinkAttr, instr, attr);
      at_set(rc, funci, attr);
      tt_set(rc, funci, TT_OTHER);
      if(LMN_ATTR_IS_DATA(attr)) {
        READ_CONST_DATA_ATOM(wt(rc, funci), at(rc, funci), tt(rc, funci));
      }
      else {
        LmnFunctor f;

        READ_VAL(LmnFunctor, instr, f);
        wt_set(rc, funci, f);
        tt_set(rc, funci, TT_OTHER);
      }
      break;
    }
    case INSTR_EQFUNC:
    {
      LmnInstrVar func0;
      LmnInstrVar func1;

      READ_VAL(LmnFunctor, instr, func0);
      READ_VAL(LmnFunctor, instr, func1);

      if (at(rc, func0) != at(rc, func1)) return FALSE;
      switch (at(rc, func0)) {
      case LMN_INT_ATTR:
        if ((long)wt(rc, func0) != (long)wt(rc, func1)) return FALSE;
        break;
      case LMN_DBL_ATTR:
        if (*(double *)(wt(rc, func0)) !=
            *(double *)(wt(rc, func1))) return FALSE;
        break;
      case LMN_HL_ATTR:
        if (!lmn_hyperlink_eq_hl(lmn_hyperlink_at_to_hl(LMN_SATOM(wt(rc, func0))),
                                 lmn_hyperlink_at_to_hl(LMN_SATOM(wt(rc, func1)))))
          return FALSE;
        break;
      default:
        if (wt(rc, func0) != wt(rc, func1)) return FALSE;
        break;
      }
      break;
    }
    case INSTR_NEQFUNC:
    {
      LmnInstrVar func0;
      LmnInstrVar func1;

      READ_VAL(LmnFunctor, instr, func0);
      READ_VAL(LmnFunctor, instr, func1);

      if (at(rc, func0) == at(rc, func1)) {
        switch (at(rc, func0)) {
        case LMN_INT_ATTR:
          if ((long)wt(rc, func0) == (long)wt(rc, func1)) return FALSE;
          break;
        case LMN_DBL_ATTR:
          if (*(double *)(wt(rc, func0)) ==
              *(double *)(wt(rc, func1))) return FALSE;
          break;
        case LMN_HL_ATTR:
          if (lmn_hyperlink_eq_hl(lmn_hyperlink_at_to_hl(LMN_SATOM(wt(rc, func0))),
                                  lmn_hyperlink_at_to_hl(LMN_SATOM(wt(rc, func1)))))
            return FALSE;
          break;
        default:
          if (wt(rc, func0) == wt(rc, func1)) return FALSE;
          break;
        }
      }
      break;
    }
    case INSTR_ADDATOM:
    {
      LmnInstrVar memi, atomi;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, atomi);
      lmn_mem_push_atom((LmnMembrane *)wt(rc, memi), wt(rc, atomi), at(rc, atomi));
      break;
    }
    case INSTR_MOVECELLS:
    {
      LmnInstrVar destmemi, srcmemi;

      READ_VAL(LmnInstrVar, instr, destmemi);
      READ_VAL(LmnInstrVar, instr, srcmemi);
      LMN_ASSERT(wt(rc, destmemi) != wt(rc, srcmemi));
      lmn_mem_move_cells((LmnMembrane *)wt(rc, destmemi),
                         (LmnMembrane *)wt(rc, srcmemi));
      break;
    }
    case INSTR_REMOVETEMPORARYPROXIES:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      lmn_mem_remove_temporary_proxies((LmnMembrane *)wt(rc, memi));
      break;
    }
    case INSTR_NFREELINKS:
    {
      LmnInstrVar memi, count;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, count);

      if (!lmn_mem_nfreelinks((LmnMembrane *)wt(rc, memi), count)) return FALSE;

      if (RC_GET_MODE(rc, REACT_ND) && RC_MC_USE_DPOR(rc)) {
        LmnMembrane *m = (LmnMembrane *)wt(rc, memi);
        dpor_LHS_flag_add(RC_POR_DATA(rc), lmn_mem_id(m), LHS_MEM_NFLINKS);
        interpret(rc, rule, instr);
        dpor_LHS_flag_remove(RC_POR_DATA(rc), lmn_mem_id(m), LHS_MEM_NFLINKS);
        return FALSE; /* 全ての候補取得のためにNDは常にFALSEを返す仕様 */
      }

      break;
    }
    case INSTR_COPYCELLS:
    {
      LmnInstrVar mapi, destmemi, srcmemi;

      READ_VAL(LmnInstrVar, instr, mapi);
      READ_VAL(LmnInstrVar, instr, destmemi);
      READ_VAL(LmnInstrVar, instr, srcmemi);
      wt_set(rc, mapi,
             lmn_mem_copy_cells((LmnMembrane *)wt(rc, destmemi),
                                (LmnMembrane *)wt(rc, srcmemi)));
      tt_set(rc, mapi, TT_OTHER);
      break;
    }
    case INSTR_LOOKUPLINK:
    {
      LmnInstrVar destlinki, tbli, srclinki;

      READ_VAL(LmnInstrVar, instr, destlinki);
      READ_VAL(LmnInstrVar, instr, tbli);
      READ_VAL(LmnInstrVar, instr, srclinki);

      at_set(rc, destlinki, LINKED_ATTR(srclinki));
      tt_set(rc, destlinki, TT_ATOM);
      if (LMN_ATTR_IS_DATA(LINKED_ATTR(srclinki))) {
        wt_set(rc, destlinki, LINKED_ATOM(srclinki));
      } else { /* symbol atom */
        ProcessTbl ht = (ProcessTbl)wt(rc, tbli);
        proc_tbl_get_by_atom(ht, LMN_SATOM(LINKED_ATOM(srclinki)), &wt(rc, destlinki));
      }
      break;
    }
    case INSTR_CLEARRULES:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      lmn_mem_clearrules((LmnMembrane *)wt(rc, memi));
      break;
    }
    case INSTR_DROPMEM:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      lmn_mem_drop((LmnMembrane *)wt(rc, memi));
      break;
    }
    case INSTR_TESTMEM:
    {
      LmnInstrVar memi, atomi;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, atomi);
      LMN_ASSERT(!LMN_ATTR_IS_DATA(at(rc, atomi)));
      LMN_ASSERT(LMN_IS_PROXY_FUNCTOR(LMN_SATOM_GET_FUNCTOR(wt(rc, atomi))));

      if (LMN_PROXY_GET_MEM(wt(rc, atomi)) != (LmnMembrane *)wt(rc, memi)) return FALSE;
      break;
    }
    case INSTR_IADDFUNC:
    {
      LmnInstrVar desti, i0, i1;

      READ_VAL(LmnInstrVar, instr, desti);
      READ_VAL(LmnInstrVar, instr, i0);
      READ_VAL(LmnInstrVar, instr, i1);
      LMN_ASSERT(at(rc, i0) == LMN_INT_ATTR);
      LMN_ASSERT(at(rc, i1) == LMN_INT_ATTR);
      warry_set(rc, desti, wt(rc, i0) + wt(rc, i1), LMN_INT_ATTR, TT_ATOM);
      break;
    }
    case INSTR_ISUBFUNC:
    {
      LmnInstrVar desti, i0, i1;

      READ_VAL(LmnInstrVar, instr, desti);
      READ_VAL(LmnInstrVar, instr, i0);
      READ_VAL(LmnInstrVar, instr, i1);
      LMN_ASSERT(at(rc, i0) == LMN_INT_ATTR);
      LMN_ASSERT(at(rc, i1) == LMN_INT_ATTR);
      warry_set(rc, desti, wt(rc, i0) - wt(rc, i1), LMN_INT_ATTR, TT_ATOM);
      break;
    }
    case INSTR_IMULFUNC:
    {
      LmnInstrVar desti, i0, i1;

      READ_VAL(LmnInstrVar, instr, desti);
      READ_VAL(LmnInstrVar, instr, i0);
      READ_VAL(LmnInstrVar, instr, i1);
      LMN_ASSERT(at(rc, i0) == LMN_INT_ATTR);
      LMN_ASSERT(at(rc, i1) == LMN_INT_ATTR);
      warry_set(rc, desti, wt(rc, i0) * wt(rc, i1), LMN_INT_ATTR, TT_ATOM);
      break;
    }
    case INSTR_IDIVFUNC:
    {
      LmnInstrVar desti, i0, i1;

      READ_VAL(LmnInstrVar, instr, desti);
      READ_VAL(LmnInstrVar, instr, i0);
      READ_VAL(LmnInstrVar, instr, i1);
      LMN_ASSERT(at(rc, i0) == LMN_INT_ATTR);
      LMN_ASSERT(at(rc, i1) == LMN_INT_ATTR);
      warry_set(rc, desti, wt(rc, i0) / wt(rc, i1), LMN_INT_ATTR, TT_ATOM);
      break;
    }
    case INSTR_IMODFUNC:
    {
      LmnInstrVar desti, i0, i1;

      READ_VAL(LmnInstrVar, instr, desti);
      READ_VAL(LmnInstrVar, instr, i0);
      READ_VAL(LmnInstrVar, instr, i1);
      LMN_ASSERT(at(rc, i0) == LMN_INT_ATTR);
      LMN_ASSERT(at(rc, i1) == LMN_INT_ATTR);
      warry_set(rc, desti, wt(rc, i0) % wt(rc, i1), LMN_INT_ATTR, TT_ATOM);
      break;
    }
    case INSTR_GROUP:
    {
      LmnSubInstrSize subinstr_size;
      READ_VAL(LmnSubInstrSize, instr, subinstr_size);

      if (!interpret(rc, rule, instr)) return FALSE;
      instr += subinstr_size;
      break;
    }
    case INSTR_BRANCH:
    {
      LmnSubInstrSize subinstr_size;
      READ_VAL(LmnSubInstrSize, instr, subinstr_size);

      if (RC_HLINK_SPC(rc)) {
        lmn_sameproccxt_clear(rc); /*branchとhyperlinkを同時起動するための急場しのぎ */
      }
      if (interpret(rc, rule, instr)) return TRUE;
      instr += subinstr_size;
      break;
    }
    case INSTR_LOOP:
    {
      LmnSubInstrSize subinstr_size;
      READ_VAL(LmnSubInstrSize, instr, subinstr_size);

      while (interpret(rc, rule, instr)) ;
      instr += subinstr_size;
      break;
    }
    case INSTR_CALLBACK:
    {
      LmnInstrVar memi, atomi;
      LmnSAtom atom;
      const struct CCallback *c;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, atomi);

      atom = LMN_SATOM(wt(rc, atomi));

      if (!LMN_ATTR_IS_DATA(LMN_SATOM_GET_ATTR(atom, 0))) {
        LmnSAtom f_name = LMN_SATOM(LMN_SATOM_GET_LINK(atom, 0));
        lmn_interned_str name = LMN_FUNCTOR_NAME_ID(LMN_SATOM_GET_FUNCTOR(f_name));
        int arity = LMN_FUNCTOR_ARITY(LMN_SATOM_GET_FUNCTOR(atom));

        c = get_ccallback(name);
        if (!c) break;

        if (arity-1 != c->arity) {
          fprintf(stderr, "EXTERNAL FUNC: invalid arity - %s\n", LMN_SYMBOL_STR(name));
          break;
        }

        lmn_mem_delete_atom((LmnMembrane *)wt(rc, memi), wt(rc, atomi), at(rc, atomi));
        lmn_mem_delete_atom((LmnMembrane *)wt(rc, memi),
                            LMN_SATOM_GET_LINK(atom, 0),
                            LMN_SATOM_GET_ATTR(atom, 0));

        switch (arity) {
        case 1:
          ((callback_0)c->f)(rc, (LmnMembrane *)wt(rc, memi));
          break;
        case 2:
          ((callback_1)c->f)(rc,
                             (LmnMembrane *)wt(rc, memi),
                             LMN_SATOM_GET_LINK(atom, 1), LMN_SATOM_GET_ATTR(atom, 1));
          break;
        case 3:
          ((callback_2)c->f)(rc,
                             (LmnMembrane *)wt(rc, memi),
                             LMN_SATOM_GET_LINK(atom, 1), LMN_SATOM_GET_ATTR(atom, 1),
                             LMN_SATOM_GET_LINK(atom, 2), LMN_SATOM_GET_ATTR(atom, 2));
          break;
        case 4:
          ((callback_3)c->f)(rc,
                             (LmnMembrane *)wt(rc, memi),
                             LMN_SATOM_GET_LINK(atom, 1), LMN_SATOM_GET_ATTR(atom, 1),
                             LMN_SATOM_GET_LINK(atom, 2), LMN_SATOM_GET_ATTR(atom, 2),
                             LMN_SATOM_GET_LINK(atom, 3), LMN_SATOM_GET_ATTR(atom, 3));
          break;
        case 5:
          ((callback_4)c->f)(rc,
                             (LmnMembrane *)wt(rc, memi),
                             LMN_SATOM_GET_LINK(atom, 1), LMN_SATOM_GET_ATTR(atom, 1),
                             LMN_SATOM_GET_LINK(atom, 2), LMN_SATOM_GET_ATTR(atom, 2),
                             LMN_SATOM_GET_LINK(atom, 3), LMN_SATOM_GET_ATTR(atom, 3),
                             LMN_SATOM_GET_LINK(atom, 4), LMN_SATOM_GET_ATTR(atom, 4));
          break;
        default:
          printf("EXTERNAL FUNCTION: too many arguments\n");
          break;
        }
      }

      break;
    }
    case INSTR_GETCLASS:
    {
      LmnInstrVar reti, atomi;

      READ_VAL(LmnInstrVar, instr, reti);
      READ_VAL(LmnInstrVar, instr, atomi);

      tt_set(rc, reti, TT_OTHER);
      if (LMN_ATTR_IS_DATA(at(rc, atomi))) {
        switch (at(rc, atomi)) {
        case LMN_INT_ATTR:
          wt_set(rc, reti, lmn_intern("int"));
          break;
        case LMN_DBL_ATTR:
          wt_set(rc, reti, lmn_intern("float"));
          break;
        case LMN_SP_ATOM_ATTR:
          wt_set(rc, reti, SP_ATOM_NAME(wt(rc, atomi)));
          break;
        default:
          wt_set(rc, reti, lmn_intern("unknown"));
          break;
        }
      } else { /* symbol atom */
        wt_set(rc, reti, lmn_intern("symbol"));
      }
      break;
    }
    case INSTR_SUBCLASS:
    {
      LmnInstrVar subi, superi;

      READ_VAL(LmnInstrVar, instr, subi);
      READ_VAL(LmnInstrVar, instr, superi);

      /* サブやスーパークラスなどの階層の概念がないので単純比較を行う */
      if (wt(rc, subi) != wt(rc, superi)) return FALSE;
      break;
    }
    case INSTR_CELLDUMP:
    {
      printf("CELL DUMP:\n");
      lmn_dump_cell_stdout(RC_GROOT_MEM(rc));
      lmn_hyperlink_print(RC_GROOT_MEM(rc));
      break;
    }
    default:
      fprintf(stderr, "interpret: Unknown operation %d\n", op);
      exit(1);
    }
/*     lmn_dump_mem((LmnMembrane *)wt(rc, 0)); */
/*     print_wt(); */

    #ifdef DEBUG
/*     print_wt(); */
    #endif
  }
}

/* DEBUG: */
/* static void print_wt(void) */
/* { */
/*   unsigned int i; */
/*   unsigned int end = 16; */

/*   fprintf(stderr, " wt: ["); */
/*   for (i = 0; i < end; i++) { */
/*     if (i>0) fprintf(stderr, ", "); */
/*     fprintf(stderr, "%lu", wt(rc, i)); */
/*   } */
/*   fprintf(stderr, "]"); */
/*   fprintf(stderr, "\n"); */
/*   fprintf(stderr, " at: ["); */
/*   for (i = 0; i < end; i++) { */
/*     if (i>0) fprintf(stderr, ", "); */
/*     fprintf(stderr, "%u", at(rc, i)); */
/*   } */
/*   fprintf(stderr, "]"); */
/*   fprintf(stderr, "\n"); */
/* } */


static BOOL dmem_interpret(LmnReactCxt *rc, LmnRule rule, LmnRuleInstr instr)
{
/*   LmnRuleInstr start = instr; */
  LmnInstrOp op;

  while (TRUE) {
    READ_VAL(LmnInstrOp, instr, op);
/*     fprintf(stdout, "op: %d %d\n", op, (instr - start)); */
/*     lmn_dump_mem((LmnMembrane*)wt(rc, 0)); */
    switch (op) {
    case INSTR_SPEC:
    {
      LmnInstrVar s0, s1;

      READ_VAL(LmnInstrVar, instr, s0);
      READ_VAL(LmnInstrVar, instr, s1);

      if (s1 > warry_size(rc)) {
        lmn_register_extend(rc, s1);
      }
      warry_use_size_set(rc, s1);
      warry_cur_size_set(rc, 0);
      break;
    }
    case INSTR_INSERTCONNECTORSINNULL:
    {
      LmnInstrVar seti, list_num;
      Vector links;
      unsigned int i;

      READ_VAL(LmnInstrVar, instr, seti);
      READ_VAL(LmnInstrVar, instr, list_num);

      vec_init(&links, list_num + 1);
      for (i = 0; i < list_num; i++) {
        LmnInstrVar t;
        READ_VAL(LmnInstrVar, instr, t);
        vec_push(&links, (LmnWord)t);
      }

      warry_set(rc, seti, insertconnectors(rc, NULL, &links), 0, TT_OTHER);
      vec_destroy(&links);

      /* EFFICIENCY: 解放のための再帰 */
      if (dmem_interpret(rc, rule, instr)) {
        hashset_free((HashSet *)wt(rc, seti));
        return TRUE;
      } else {
        LMN_ASSERT(0);
      }
      break;
    }
    case INSTR_INSERTCONNECTORS:
    {
      LmnInstrVar seti, list_num, memi, enti;
      Vector links; /* src list */
      unsigned int i;

      READ_VAL(LmnInstrVar, instr, seti);
      READ_VAL(LmnInstrVar, instr, list_num);

      vec_init(&links, list_num + 1);

      for (i = 0; i < list_num; i++) {
        READ_VAL(LmnInstrVar, instr, enti);
        vec_push(&links, (LmnWord)enti);
      }

      READ_VAL(LmnInstrVar, instr, memi);

      warry_set(rc, seti,
                insertconnectors(rc, (LmnMembrane *)wt(rc, memi), &links),
                0,
                TT_OTHER);
      vec_destroy(&links);

      /* EFFICIENCY: 解放のための再帰 */
      if (dmem_interpret(rc, rule, instr)) {
        hashset_free((HashSet *)wt(rc, seti));
        return TRUE;
      } else {
        LMN_ASSERT(0);
      }
      break;
    }
    case INSTR_NEWATOM:
    {
      LmnInstrVar atomi, memi;
      LmnAtom ap;
      LmnLinkAttr attr;

      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnLinkAttr, instr, attr);
      if (LMN_ATTR_IS_DATA(attr)) {
        READ_DATA_ATOM(ap, attr);
      } else { /* symbol atom */
        LmnFunctor f;

        READ_VAL(LmnFunctor, instr, f);
        ap = LMN_ATOM(dmem_root_new_atom(RC_ND_MEM_DELTA_ROOT(rc), f));
      }

      dmem_root_push_atom(RC_ND_MEM_DELTA_ROOT(rc),
                          (LmnMembrane *)wt(rc, memi), ap, attr);
      warry_set(rc, atomi, ap, attr, TT_OTHER); /* BODY命令のアトムなのでコピー対象にしない->TT_OTHER */
      break;
    }
    case INSTR_COPYATOM:
    {
      LmnInstrVar atom1, memi, atom2;

      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, atom2);

      warry_set(rc, atom1,
                dmem_root_copy_atom(RC_ND_MEM_DELTA_ROOT(rc), wt(rc, atom2), at(rc, atom2)),
                at(rc, atom2),
                TT_OTHER);
      dmem_root_push_atom(RC_ND_MEM_DELTA_ROOT(rc),
                          (LmnMembrane *)wt(rc, memi), wt(rc, atom1), at(rc, atom1));
      break;
    }
    case INSTR_ALLOCLINK:
    {
      LmnInstrVar link, atom, n;

      READ_VAL(LmnInstrVar, instr, link);
      READ_VAL(LmnInstrVar, instr, atom);
      READ_VAL(LmnInstrVar, instr, n);

      if (LMN_ATTR_IS_DATA(at(rc, atom))) {
        wt_set(rc, link, wt(rc, atom));
        at_set(rc, link, at(rc, atom));
      } else { /* link to atom */
        wt_set(rc, link, LMN_SATOM(wt(rc, atom)));
        at_set(rc, link, LMN_ATTR_MAKE_LINK(n));
      }
      tt_set(rc, link, TT_OTHER);
      break;
    }
    case INSTR_UNIFYLINKS:
    {
      LmnInstrVar link1, link2, mem;

      READ_VAL(LmnInstrVar, instr, link1);
      READ_VAL(LmnInstrVar, instr, link2);
      READ_VAL(LmnInstrVar, instr, mem);

      if (LMN_ATTR_IS_DATA(LINKED_ATTR(link1))) {
        if (LMN_ATTR_IS_DATA(LINKED_ATTR(link2))) { /* 1, 2 are data */
          dmem_root_link_data_atoms(RC_ND_MEM_DELTA_ROOT(rc),
                                    (LmnMembrane *)wt(rc, mem),
                                    LINKED_ATOM(link1), LINKED_ATTR(link1),
                                    LINKED_ATOM(link2), LINKED_ATTR(link2));
        } else { /* 1 is data */
          dmem_root_unify_links(RC_ND_MEM_DELTA_ROOT(rc),
                                (LmnMembrane *)wt(rc, mem),
                                LINKED_ATOM(link2), LINKED_ATTR(link2),
                                LINKED_ATOM(link1), LINKED_ATTR(link1));
        }
      }
      else { /* 2 is data or 1, 2 are symbol atom */
        dmem_root_unify_links(RC_ND_MEM_DELTA_ROOT(rc),
                              (LmnMembrane *)wt(rc, mem),
                              LINKED_ATOM(link1), LINKED_ATTR(link1),
                              LINKED_ATOM(link2), LINKED_ATTR(link2));
      }
      break;
    }
    case INSTR_NEWLINK:
    {
      LmnInstrVar atom1, atom2, pos1, pos2, memi;

      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, pos1);
      READ_VAL(LmnInstrVar, instr, atom2);
      READ_VAL(LmnInstrVar, instr, pos2);
      READ_VAL(LmnInstrVar, instr, memi);

      dmem_root_newlink(RC_ND_MEM_DELTA_ROOT(rc),
                        (LmnMembrane *)wt(rc, memi),
                        wt(rc, atom1), at(rc, atom1), pos1,
                        wt(rc, atom2), at(rc, atom2), pos2);
      break;
    }
    case INSTR_RELINK:
    {
      LmnInstrVar atom1, atom2, pos1, pos2, memi;

      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, pos1);
      READ_VAL(LmnInstrVar, instr, atom2);
      READ_VAL(LmnInstrVar, instr, pos2);
      READ_VAL(LmnInstrVar, instr, memi);

      dmem_root_relink(RC_ND_MEM_DELTA_ROOT(rc),
                       (LmnMembrane *)wt(rc, memi),
                       wt(rc, atom1), at(rc, atom1), pos1,
                       wt(rc, atom2), at(rc, atom2), pos2);
      break;
    }
    case INSTR_GETLINK:
    {
      LmnInstrVar linki, atomi, posi;
      READ_VAL(LmnInstrVar, instr, linki);
      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnInstrVar, instr, posi);

      wt_set(rc, linki, dmem_root_get_link(RC_ND_MEM_DELTA_ROOT(rc), LMN_SATOM(wt(rc, atomi)), posi));
      at_set(rc, linki, LMN_SATOM_GET_ATTR(wt(rc, atomi), posi));
      tt_set(rc, linki, TT_OTHER);
      break;
    }
    case INSTR_UNIFY:
    {
      LmnInstrVar atom1, pos1, atom2, pos2, memi;

      READ_VAL(LmnInstrVar, instr, atom1);
      READ_VAL(LmnInstrVar, instr, pos1);
      READ_VAL(LmnInstrVar, instr, atom2);
      READ_VAL(LmnInstrVar, instr, pos2);
      READ_VAL(LmnInstrVar, instr, memi);

      dmem_root_unify_atom_args(RC_ND_MEM_DELTA_ROOT(rc),
                                (LmnMembrane *)wt(rc, memi),
                                LMN_SATOM(wt(rc, atom1)), pos1,
                                LMN_SATOM(wt(rc, atom2)), pos2);
      break;
    }
    case INSTR_PROCEED:
      return TRUE;
    case INSTR_STOP:
      return FALSE;
    case INSTR_ENQUEUEATOM:
    {
      LmnInstrVar atom;

      READ_VAL(LmnInstrVar, instr, atom);
      /* do nothing */
      break;
    }
    case INSTR_DEQUEUEATOM:
    {
      LmnInstrVar atom;

      READ_VAL(LmnInstrVar, instr, atom);
      break;
    }
    case INSTR_NEWMEM:
    {
      LmnInstrVar newmemi, parentmemi, memf;
      LmnMembrane *mp;

      READ_VAL(LmnInstrVar, instr, newmemi);
      READ_VAL(LmnInstrVar, instr, parentmemi);
      READ_VAL(LmnInstrVar, instr, memf);

      mp = dmem_root_new_mem(RC_ND_MEM_DELTA_ROOT(rc)); /*lmn_new_mem(memf);*/
      dmem_root_add_child_mem(RC_ND_MEM_DELTA_ROOT(rc),
                              (LmnMembrane*)wt(rc, parentmemi), mp);
      wt_set(rc, newmemi, mp);
      tt_set(rc, newmemi, TT_OTHER);
      lmn_mem_set_active(mp, TRUE);
      if (RC_GET_MODE(rc, REACT_MEM_ORIENTED)) {
        lmn_memstack_push(RC_MEMSTACK(rc), mp);
      }
      break;
    }
    case INSTR_ALLOCMEM:
    {
      LmnInstrVar dstmemi;

      READ_VAL(LmnInstrVar, instr, dstmemi);

      wt_set(rc, dstmemi, dmem_root_new_mem(RC_ND_MEM_DELTA_ROOT(rc)));
      tt_set(rc, dstmemi, TT_OTHER);
      break;
    }
    case INSTR_REMOVEATOM:
    {
      LmnInstrVar atomi, memi;

      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnInstrVar, instr, memi);

      dmem_root_remove_atom(RC_ND_MEM_DELTA_ROOT(rc),
                            (LmnMembrane*)wt(rc, memi),
                            wt(rc, atomi), at(rc, atomi));
      break;
    }
    case INSTR_FREEATOM:
    {
      LmnInstrVar atomi;

      READ_VAL(LmnInstrVar, instr, atomi);

      dmem_root_free_atom(RC_ND_MEM_DELTA_ROOT(rc), wt(rc, atomi), at(rc, atomi));
      break;
    }
    case INSTR_REMOVEMEM:
    {
      LmnInstrVar memi, parenti;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, parenti);

      dmem_root_remove_mem(RC_ND_MEM_DELTA_ROOT(rc),
                           (LmnMembrane *)wt(rc, parenti), (LmnMembrane *)wt(rc, memi));
      break;
    }
    case INSTR_FREEMEM:
    {
      LmnInstrVar memi;
      LmnMembrane *mp;

      READ_VAL(LmnInstrVar, instr, memi);

      mp = (LmnMembrane*)wt(rc, memi);
/*       lmn_mem_free(mp); */
      break;
    }
    case INSTR_ADDMEM:
    {
      LmnInstrVar dstmem, srcmem;

      READ_VAL(LmnInstrVar, instr, dstmem);
      READ_VAL(LmnInstrVar, instr, srcmem);

//      LMN_ASSERT(!((LmnMembrane *)wt(rc, srcmem))->parent);

//      lmn_mem_add_child_mem((LmnMembrane *)wt(rc, dstmem), (LmnMembrane *)wt(rc, srcmem));
      dmem_root_add_child_mem(RC_ND_MEM_DELTA_ROOT(rc),
                              (LmnMembrane *)wt(rc, dstmem),
                              (LmnMembrane *)wt(rc, srcmem));
      break;

      break;
    }
    case INSTR_ENQUEUEMEM:
    {
      LmnInstrVar memi;
      READ_VAL(LmnInstrVar, instr, memi);
//      if (RC_GET_MODE(rc, REACT_ND)) {
//        lmn_mem_activate_ancestors((LmnMembrane *)wt(rc, memi)); /* MC */
//      }
      /* 通常実行ではdmem_interpretを使用しないため以下のコードは不要.
       * ただ, 通常実行用dmemはテスト用やinteractive実行用として作っておいてもよさそう */
//      if (RC_GET_MODE(rc, REACT_MEM_ORIENTED)) {
//        lmn_memstack_push(RC_MEMSTACK(rc), (LmnMembrane *)wt(rc, memi)); /* 通常実行時 */
//      }
      break;
    }
    case INSTR_UNLOCKMEM:
    {
      LmnInstrVar memi;
      READ_VAL(LmnInstrVar, instr, memi);

      break;
    }
    case INSTR_LOADRULESET:
    {
      LmnInstrVar memi;
      LmnRulesetId id;
      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnRulesetId, instr, id);

      lmn_mem_add_ruleset((LmnMembrane*)wt(rc, memi), lmn_ruleset_from_id(id));
      break;
    }
    case INSTR_LOADMODULE:
    {
      LmnInstrVar memi;
      lmn_interned_str module_name_id;
      LmnRuleSet ruleset;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(lmn_interned_str, instr, module_name_id);

      if ((ruleset = lmn_get_module_ruleset(module_name_id))) {
        /* テーブル内にルールセットがある場合 */
        lmn_mem_add_ruleset((LmnMembrane*)wt(rc, memi), ruleset);
      }
      else {
        /* テーブル内にルールセットがない場合 */
        fprintf(stderr, "Undefined module %s\n", lmn_id_to_name(module_name_id));
      }
      break;
    }
    case INSTR_RECURSIVELOCK:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      /* do notiong */
      break;
    }
    case INSTR_RECURSIVEUNLOCK:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      /* do notiong */
      break;
    }
    case INSTR_COPYGROUND:
    {
      LmnInstrVar dstlist, srclist, memi;
      Vector *srcvec, *dstlovec, *retvec; /* 変数番号のリスト */
      ProcessTbl atommap;

      READ_VAL(LmnInstrVar, instr, dstlist);
      READ_VAL(LmnInstrVar, instr, srclist);
      READ_VAL(LmnInstrVar, instr, memi);

      /* リンクオブジェクトのベクタを構築 */
      srcvec = links_from_idxs((Vector *)wt(rc, srclist), rc_warry(rc));

      dmem_root_copy_ground(RC_ND_MEM_DELTA_ROOT(rc),
                            (LmnMembrane *)wt(rc, memi),
                            srcvec,
                            &dstlovec,
                            &atommap);
      free_links(srcvec);

      /* 返り値の作成 */
      retvec = vec_make(2);
      vec_push(retvec, (LmnWord)dstlovec);
      vec_push(retvec, (LmnWord)atommap);
      warry_set(rc, dstlist, retvec, LIST_AND_MAP, TT_OTHER);

      /* 解放のための再帰。ベクタを解放するための中間語命令がない */
      dmem_interpret(rc, rule, instr);

      free_links(dstlovec);
      vec_free(retvec);

      return TRUE; /* COPYGROUNDはボディに出現する */
    }
    case INSTR_REMOVEGROUND:
    case INSTR_FREEGROUND:
    {
      LmnInstrVar listi, memi;
      Vector *srcvec; /* 変数番号のリスト */

      memi = 0; /* warningを黙らす */
      READ_VAL(LmnInstrVar, instr, listi);
      if (INSTR_REMOVEGROUND == op) {
         READ_VAL(LmnInstrVar, instr, memi);
      }

      srcvec = links_from_idxs((Vector *)wt(rc, listi), rc_warry(rc));

      switch (op) {
       case INSTR_REMOVEGROUND:
         dmem_root_remove_ground(RC_ND_MEM_DELTA_ROOT(rc), (LmnMembrane *)wt(rc, memi), srcvec);
         break;
       case INSTR_FREEGROUND:
         /* memを使い回す関係上freeするとまずい */
//         dmem_root_free_ground(RC_ND_MEM_DELTA_ROOT(rc), srcvec);
         break;
      }

      free_links(srcvec);

      break;
    }
    case INSTR_NEWLIST:
    {
      LmnInstrVar listi;
      Vector *listvec = vec_make(16);
      READ_VAL(LmnInstrVar, instr, listi);
      warry_set(rc, listi, listvec, 0, TT_OTHER);

      if (dmem_interpret(rc, rule, instr)) {
        vec_free(listvec);
        return TRUE;
      }
      else {
        vec_free(listvec);
        return FALSE;
      }
      break;
    }
    case INSTR_ADDTOLIST:
    {
      LmnInstrVar listi, linki;
      READ_VAL(LmnInstrVar, instr, listi);
      READ_VAL(LmnInstrVar, instr, linki);
      vec_push((Vector *)wt(rc, listi), linki);
      break;
    }
    case INSTR_GETFROMLIST:
    {
      LmnInstrVar dsti, listi, posi;
      READ_VAL(LmnInstrVar, instr, dsti);
      READ_VAL(LmnInstrVar, instr, listi);
      READ_VAL(LmnInstrVar, instr, posi);

      switch (at(rc, listi)) {
        case LIST_AND_MAP:

          if (posi == 0) {
            warry_set(rc, dsti,
                      vec_get((Vector *)wt(rc, listi), (unsigned int)posi),
                      LINK_LIST,
                      TT_OTHER);
          } else if (posi == 1) {
            warry_set(rc, dsti,
                      vec_get((Vector *)wt(rc, listi), (unsigned int)posi),
                      MAP,
                      TT_OTHER);
          } else {
            LMN_ASSERT(0);
          }
          break;
        case LINK_LIST: /* LinkObjをfreeするのはここ？ */
        {
          LinkObj lo = (LinkObj)vec_get((Vector *)wt(rc, listi), (unsigned int)posi);
          wt_set(rc, dsti, lo->ap);
          at_set(rc, dsti, lo->pos);
          break;
        }
        default:
          lmn_fatal("unexpected.");
          break;
      }
      break;
    }
    case INSTR_ALLOCATOM:
    {
      LmnInstrVar atomi;
      LmnLinkAttr attr;

      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnLinkAttr, instr, attr);

      at_set(rc, atomi, attr);
      if (LMN_ATTR_IS_DATA(attr)) {
        READ_CONST_DATA_ATOM(wt(rc, atomi), at(rc, atomi), tt(rc, atomi));
      } else { /* symbol atom */
        LmnFunctor f;
/*         fprintf(stderr, "symbol atom can't be created in GUARD\n"); */
/*         exit(EXIT_FAILURE); */
        READ_VAL(LmnFunctor, instr, f);

        /* 本来のallocatomは格納するのは定数アトムだが、簡単のためにファンクタを格納する */
        wt_set(rc, atomi, f);
      }
      tt_set(rc, atomi, TT_OTHER);
      break;
    }
    case INSTR_ALLOCATOMINDIRECT:
    {
      LmnInstrVar atomi;
      LmnInstrVar srcatomi;

      READ_VAL(LmnInstrVar, instr, atomi);
      READ_VAL(LmnInstrVar, instr, srcatomi);

      if (LMN_ATTR_IS_DATA(at(rc, srcatomi))) {
        warry_set(rc, atomi,
                  lmn_copy_data_atom(wt(rc, srcatomi), at(rc, srcatomi)),
                  at(rc, srcatomi),
                  TT_OTHER);
      } else { /* symbol atom */
        fprintf(stderr, "symbol atom can't be created in GUARD\n");
        exit(EXIT_FAILURE);
      }
      break;
    }
    case INSTR_GETFUNC:
    {
      LmnInstrVar funci, atomi;

      READ_VAL(LmnInstrVar, instr, funci);
      READ_VAL(LmnInstrVar, instr, atomi);

      if(LMN_ATTR_IS_DATA(at(rc, atomi))) {
        /* ここで得るファンクタはガード命令中で一時的に使われるだけなので
           double はポインタのコピーで十分なはず */
        wt_set(rc, funci, wt(rc, atomi));
      }
      else {
        wt_set(rc, funci, LMN_SATOM_GET_FUNCTOR(wt(rc, atomi)));
      }
      at_set(rc, funci, at(rc, atomi));
      tt_set(rc, funci, TT_OTHER);
      break;
    }
    case INSTR_SETMEMNAME:
    {
      LmnInstrVar memi;
      lmn_interned_str name;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(lmn_interned_str, instr, name);
      dmem_root_set_mem_name(RC_ND_MEM_DELTA_ROOT(rc), (LmnMembrane *)wt(rc, memi), name);
      break;
    }
    case INSTR_COPYRULES:
    {
      LmnInstrVar destmemi, srcmemi;

      READ_VAL(LmnInstrVar, instr, destmemi);
      READ_VAL(LmnInstrVar, instr, srcmemi);

      dmem_root_copy_rules(RC_ND_MEM_DELTA_ROOT(rc),
                           (LmnMembrane *)wt(rc, destmemi),
                           (LmnMembrane *)wt(rc, srcmemi));
      break;
    }
    case INSTR_REMOVEPROXIES:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      dmem_root_remove_proxies(RC_ND_MEM_DELTA_ROOT(rc), (LmnMembrane *)wt(rc, memi));
      break;
    }
    case INSTR_INSERTPROXIES:
    {
      LmnInstrVar parentmemi, childmemi;

      READ_VAL(LmnInstrVar, instr, parentmemi);
      READ_VAL(LmnInstrVar, instr, childmemi);
      dmem_root_insert_proxies(RC_ND_MEM_DELTA_ROOT(rc),
                               (LmnMembrane *)wt(rc, parentmemi),
                               (LmnMembrane *)wt(rc, childmemi));
      break;
    }
    case INSTR_DELETECONNECTORS:
    {
      LmnInstrVar srcset, srcmap;
      HashSet *delset;
      ProcessTbl delmap;
      HashSetIterator it;
      READ_VAL(LmnInstrVar, instr, srcset);
      READ_VAL(LmnInstrVar, instr, srcmap);

      delset = (HashSet *)wt(rc, srcset);
      delmap = (ProcessTbl)wt(rc, srcmap);

      for (it = hashset_iterator(delset); !hashsetiter_isend(&it); hashsetiter_next(&it)) {
        LmnSAtom orig, copy;
        LmnWord t;

        orig = LMN_SATOM(hashsetiter_entry(&it));
        t = 0; /* warningを黙らす */
        proc_tbl_get_by_atom(delmap, orig, &t);
        copy = LMN_SATOM(t);
        lmn_mem_unify_symbol_atom_args(orig, 0, orig, 1);
        lmn_mem_unify_symbol_atom_args(copy, 0, copy, 1);

        lmn_delete_atom(orig);
        lmn_delete_atom(copy);
      }

      if (delmap) proc_tbl_free(delmap);
      break;
    }
    case INSTR_REMOVETOPLEVELPROXIES:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      dmem_root_remove_toplevel_proxies(RC_ND_MEM_DELTA_ROOT(rc), (LmnMembrane *)wt(rc, memi));
      break;
    }
    case INSTR_ADDATOM:
    {
      LmnInstrVar memi, atomi;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, atomi);
      dmem_root_push_atom(RC_ND_MEM_DELTA_ROOT(rc),
                          (LmnMembrane *)wt(rc, memi),
                          wt(rc, atomi),
                          at(rc, atomi));
      break;
    }
    case INSTR_MOVECELLS:
    {
      LmnInstrVar destmemi, srcmemi;

      READ_VAL(LmnInstrVar, instr, destmemi);
      READ_VAL(LmnInstrVar, instr, srcmemi);
      LMN_ASSERT(wt(rc, destmemi) != wt(rc, srcmemi));
      dmem_root_move_cells(RC_ND_MEM_DELTA_ROOT(rc),
                           (LmnMembrane *)wt(rc, destmemi),
                           (LmnMembrane *)wt(rc, srcmemi));
      break;
    }
    case INSTR_REMOVETEMPORARYPROXIES:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      dmem_root_remove_temporary_proxies(RC_ND_MEM_DELTA_ROOT(rc), (LmnMembrane *)wt(rc, memi));
      break;
    }
    case INSTR_COPYCELLS:
    {
      LmnInstrVar mapi, destmemi, srcmemi;

      READ_VAL(LmnInstrVar, instr, mapi);
      READ_VAL(LmnInstrVar, instr, destmemi);
      READ_VAL(LmnInstrVar, instr, srcmemi);
      dmem_root_copy_cells(RC_ND_MEM_DELTA_ROOT(rc),
                           (LmnMembrane *)wt(rc, destmemi),
                           (LmnMembrane *)wt(rc, srcmemi));
      tt_set(rc, mapi, TT_OTHER);
      break;
    }
    case INSTR_LOOKUPLINK:
    {
      LmnInstrVar destlinki, tbli, srclinki;

      READ_VAL(LmnInstrVar, instr, destlinki);
      READ_VAL(LmnInstrVar, instr, tbli);
      READ_VAL(LmnInstrVar, instr, srclinki);

      at_set(rc, destlinki, LINKED_ATTR(srclinki));
      if (LMN_ATTR_IS_DATA(LINKED_ATTR(srclinki))) {
        wt_set(rc, destlinki, LINKED_ATOM(srclinki));
      }
      else { /* symbol atom */
        ProcessTbl ht = (ProcessTbl)wt(rc, tbli);
        proc_tbl_get_by_atom(ht, LMN_SATOM(LINKED_ATOM(srclinki)), &wt(rc, destlinki));
      }
      break;
    }
    case INSTR_CLEARRULES:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      dmem_root_clear_ruleset(RC_ND_MEM_DELTA_ROOT(rc), (LmnMembrane *)wt(rc, memi));
      vec_clear(&((LmnMembrane *)wt(rc, memi))->rulesets);

      break;
    }
    case INSTR_DROPMEM:
    {
      LmnInstrVar memi;

      READ_VAL(LmnInstrVar, instr, memi);
      dmem_root_drop(RC_ND_MEM_DELTA_ROOT(rc), (LmnMembrane *)wt(rc, memi));
      break;
    }
    case INSTR_LOOP:
    {
      LmnSubInstrSize subinstr_size;
      READ_VAL(LmnSubInstrSize, instr, subinstr_size);

      while (dmem_interpret(rc, rule, instr)) ;
      instr += subinstr_size;
      break;
    }
    case INSTR_CALLBACK:
    {
      LmnInstrVar memi, atomi;
      LmnSAtom atom;
      const struct CCallback *c;

      READ_VAL(LmnInstrVar, instr, memi);
      READ_VAL(LmnInstrVar, instr, atomi);

      atom = LMN_SATOM(wt(rc, atomi));

      if (!LMN_ATTR_IS_DATA(LMN_SATOM_GET_ATTR(atom, 0))) {
        LmnSAtom f_name = LMN_SATOM(LMN_SATOM_GET_LINK(atom, 0));
        lmn_interned_str name = LMN_FUNCTOR_NAME_ID(LMN_SATOM_GET_FUNCTOR(f_name));
        int arity = LMN_FUNCTOR_ARITY(LMN_SATOM_GET_FUNCTOR(atom));

        c = get_ccallback(name);
        if (!c) break;

        if (arity-1 != c->arity) {
          fprintf(stderr, "EXTERNAL FUNC: invalid arity - %s\n", LMN_SYMBOL_STR(name));
          break;
        }

        lmn_mem_delete_atom((LmnMembrane *)wt(rc, memi), wt(rc, atomi), at(rc, atomi));
        lmn_mem_delete_atom((LmnMembrane *)wt(rc, memi),
                            LMN_SATOM_GET_LINK(atom, 0),
                            LMN_SATOM_GET_ATTR(atom, 0));

        switch (arity) {
        case 1:
          ((callback_0)c->f)(rc, (LmnMembrane *)wt(rc, memi));
          break;
        case 2:
          ((callback_1)c->f)(rc,
                             (LmnMembrane *)wt(rc, memi),
                             LMN_SATOM_GET_LINK(atom, 1), LMN_SATOM_GET_ATTR(atom, 1));
          break;
        case 3:
          ((callback_2)c->f)(rc,
                             (LmnMembrane *)wt(rc, memi),
                             LMN_SATOM_GET_LINK(atom, 1), LMN_SATOM_GET_ATTR(atom, 1),
                             LMN_SATOM_GET_LINK(atom, 2), LMN_SATOM_GET_ATTR(atom, 2));
          break;
        case 4:
          ((callback_3)c->f)(rc,
                             (LmnMembrane *)wt(rc, memi),
                             LMN_SATOM_GET_LINK(atom, 1), LMN_SATOM_GET_ATTR(atom, 1),
                             LMN_SATOM_GET_LINK(atom, 2), LMN_SATOM_GET_ATTR(atom, 2),
                             LMN_SATOM_GET_LINK(atom, 3), LMN_SATOM_GET_ATTR(atom, 3));
          break;
        case 5:
          ((callback_4)c->f)(rc,
                             (LmnMembrane *)wt(rc, memi),
                             LMN_SATOM_GET_LINK(atom, 1), LMN_SATOM_GET_ATTR(atom, 1),
                             LMN_SATOM_GET_LINK(atom, 2), LMN_SATOM_GET_ATTR(atom, 2),
                             LMN_SATOM_GET_LINK(atom, 3), LMN_SATOM_GET_ATTR(atom, 3),
                             LMN_SATOM_GET_LINK(atom, 4), LMN_SATOM_GET_ATTR(atom, 4));
          break;
        default:
          printf("EXTERNAL FUNCTION: too many arguments\n");
          break;
        }
      }

      break;
    }
    default:
      fprintf(stderr, "interpret: Unknown operation %d\n", op);
      exit(1);
    }
/*     lmn_dump_mem((LmnMembrane *)wt(rc, 0)); */
/*     print_wt(); */

    #ifdef DEBUG
/*     print_wt(); */
    #endif
  }
}

